@untemps/react-vocal 2.0.0-beta.1 → 2.0.0-beta.10

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +54 -20
  3. package/dist/index.es.js +330 -1914
  4. package/dist/index.js +2 -4
  5. package/package.json +14 -7
  6. package/.github/workflows/publish.yml +0 -32
  7. package/.husky/commit-msg +0 -1
  8. package/.husky/pre-commit +0 -1
  9. package/.prettierignore +0 -3
  10. package/.prettierrc +0 -29
  11. package/CLAUDE.md +0 -59
  12. package/assets/icon-idle.png +0 -0
  13. package/assets/icon-listening.png +0 -0
  14. package/assets/microphone.png +0 -0
  15. package/assets/react-vocal.png +0 -0
  16. package/commitlint.config.js +0 -7
  17. package/dev/index.html +0 -24
  18. package/dev/package.json +0 -18
  19. package/dev/public/index.html +0 -24
  20. package/dev/src/index.jsx +0 -45
  21. package/dev/vite.config.js +0 -10
  22. package/dev/yarn.lock +0 -201
  23. package/dist/index.es.js.map +0 -1
  24. package/dist/index.js.map +0 -1
  25. package/dist/index.umd.js +0 -9
  26. package/dist/index.umd.js.map +0 -1
  27. package/src/components/Icon.jsx +0 -24
  28. package/src/components/Vocal.jsx +0 -168
  29. package/src/components/__tests__/Icon.test.jsx +0 -38
  30. package/src/components/__tests__/Vocal.test.jsx +0 -270
  31. package/src/components/__tests__/VocalWithMockedUseVocal.test.jsx +0 -38
  32. package/src/components/__tests__/__snapshots__/Icon.test.jsx.snap +0 -21
  33. package/src/components/__tests__/__snapshots__/Vocal.test.jsx.snap +0 -28
  34. package/src/hooks/__tests__/useCommands.test.js +0 -64
  35. package/src/hooks/__tests__/useTimeout.test.js +0 -69
  36. package/src/hooks/__tests__/useVocal.test.js +0 -197
  37. package/src/hooks/useCommands.js +0 -21
  38. package/src/hooks/useTimeout.js +0 -21
  39. package/src/hooks/useVocal.js +0 -56
  40. package/src/index.js +0 -7
  41. package/vite.config.js +0 -35
  42. package/vitest.setup.js +0 -71
@@ -1,197 +0,0 @@
1
- import { renderHook } from '@testing-library/react'
2
- import { Vocal as SpeechRecognitionWrapper } from '@untemps/vocal'
3
-
4
- import useVocal from '../useVocal'
5
-
6
- vi.mock('@untemps/vocal')
7
-
8
- describe('useVocal', () => {
9
- const mockStart = vi.fn()
10
- const mockStop = vi.fn()
11
- const mockAbort = vi.fn()
12
- const mockAddEventListener = vi.fn()
13
- const mockRemoveEventListener = vi.fn()
14
- const mockCleanup = vi.fn()
15
-
16
- const mockIsSupported = vi.fn()
17
- Object.defineProperty(SpeechRecognitionWrapper, 'isSupported', {
18
- get: mockIsSupported,
19
- })
20
-
21
- describe('with no SpeechRecognition support', () => {
22
- beforeAll(() => {
23
- mockIsSupported.mockReturnValue(false)
24
- })
25
-
26
- it('cannot create SpeechRecognition instance', () => {
27
- const {
28
- result: {
29
- current: [ref],
30
- },
31
- } = renderHook(() => useVocal())
32
- expect(ref.current).toBeNull()
33
- })
34
-
35
- it('not triggers start function', () => {
36
- const {
37
- result: {
38
- current: [, { start }],
39
- },
40
- } = renderHook(() => useVocal())
41
- start()
42
- expect(mockStart).not.toHaveBeenCalled()
43
- })
44
-
45
- it('not triggers stop function', () => {
46
- const {
47
- result: {
48
- current: [, { stop }],
49
- },
50
- } = renderHook(() => useVocal())
51
- stop()
52
- expect(mockStop).not.toHaveBeenCalled()
53
- })
54
-
55
- it('not triggers abort function', () => {
56
- const {
57
- result: {
58
- current: [, { abort }],
59
- },
60
- } = renderHook(() => useVocal())
61
- abort()
62
- expect(mockAbort).not.toHaveBeenCalled()
63
- })
64
-
65
- it('not triggers clean function', () => {
66
- const {
67
- result: {
68
- current: [, { clean }],
69
- },
70
- } = renderHook(() => useVocal())
71
- clean()
72
- expect(mockCleanup).not.toHaveBeenCalled()
73
- })
74
-
75
- it('not triggers subscribe function', () => {
76
- const {
77
- result: {
78
- current: [, { subscribe }],
79
- },
80
- } = renderHook(() => useVocal())
81
- subscribe('foo', vi.fn())
82
- expect(mockAddEventListener).not.toHaveBeenCalled()
83
- })
84
-
85
- it('not triggers unsubscribe function', () => {
86
- const {
87
- result: {
88
- current: [, { unsubscribe }],
89
- },
90
- } = renderHook(() => useVocal())
91
- unsubscribe('foo', vi.fn())
92
- expect(mockRemoveEventListener).not.toHaveBeenCalled()
93
- })
94
- })
95
-
96
- describe('with SpeechRecognition support', () => {
97
- beforeAll(() => {
98
- mockIsSupported.mockReturnValue(true)
99
- })
100
-
101
- beforeEach(() => {
102
- SpeechRecognitionWrapper.mockImplementation(function () {
103
- return {
104
- start: mockStart,
105
- stop: mockStop,
106
- abort: mockAbort,
107
- addEventListener: mockAddEventListener,
108
- removeEventListener: mockRemoveEventListener,
109
- cleanup: mockCleanup,
110
- }
111
- })
112
- })
113
-
114
- afterEach(() => {
115
- SpeechRecognitionWrapper.mockReset()
116
- })
117
-
118
- it('creates SpeechRecognition instance', () => {
119
- const {
120
- result: {
121
- current: [ref],
122
- },
123
- } = renderHook(() => useVocal())
124
- expect(ref.current).toBeDefined()
125
- })
126
-
127
- it('uses custom SpeechRecognition instance', () => {
128
- const foo = new SpeechRecognitionWrapper()
129
- const {
130
- result: {
131
- current: [ref],
132
- },
133
- } = renderHook(() => useVocal(null, null, foo))
134
- expect(ref.current).toBe(foo)
135
- })
136
-
137
- it('triggers start function', () => {
138
- const {
139
- result: {
140
- current: [, { start }],
141
- },
142
- } = renderHook(() => useVocal())
143
- start()
144
- expect(mockStart).toHaveBeenCalled()
145
- })
146
-
147
- it('triggers stop function', () => {
148
- const {
149
- result: {
150
- current: [, { stop }],
151
- },
152
- } = renderHook(() => useVocal())
153
- stop()
154
- expect(mockStop).toHaveBeenCalled()
155
- })
156
-
157
- it('triggers abort function', () => {
158
- const {
159
- result: {
160
- current: [, { abort }],
161
- },
162
- } = renderHook(() => useVocal())
163
- abort()
164
- expect(mockAbort).toHaveBeenCalled()
165
- })
166
-
167
- it('triggers clean function', () => {
168
- const {
169
- result: {
170
- current: [, { clean }],
171
- },
172
- } = renderHook(() => useVocal())
173
- clean()
174
- expect(mockCleanup).toHaveBeenCalled()
175
- })
176
-
177
- it('triggers subscribe function', () => {
178
- const {
179
- result: {
180
- current: [, { subscribe }],
181
- },
182
- } = renderHook(() => useVocal())
183
- subscribe('foo', vi.fn())
184
- expect(mockAddEventListener).toHaveBeenCalled()
185
- })
186
-
187
- it('triggers unsubscribe function', () => {
188
- const {
189
- result: {
190
- current: [, { unsubscribe }],
191
- },
192
- } = renderHook(() => useVocal())
193
- unsubscribe('foo', vi.fn())
194
- expect(mockRemoveEventListener).toHaveBeenCalled()
195
- })
196
- })
197
- })
@@ -1,21 +0,0 @@
1
- import Fuse from 'fuse.js'
2
-
3
- const useCommands = (commands, precision = 0.4) => {
4
- commands = !!commands
5
- ? Object.entries(commands)?.reduce((acc, [key, value]) => ({ [key.toLowerCase()]: value }), {})
6
- : {}
7
-
8
- const triggerCommand = (input) => {
9
- const fuse = new Fuse(Object.keys(commands), { includeScore: true, ignoreLocation: true })
10
- const result = fuse.search(input).filter((r) => r.score < precision)
11
- if (!!result?.length) {
12
- const key = result[0].item.toLowerCase()
13
- return commands[key]?.(input)
14
- }
15
- return null
16
- }
17
-
18
- return triggerCommand
19
- }
20
-
21
- export default useCommands
@@ -1,21 +0,0 @@
1
- import { useCallback, useEffect, useRef } from 'react'
2
-
3
- const useTimeout = (handler, timeout = 0) => {
4
- const ref = useRef(-1)
5
-
6
- const stop = useCallback(() => {
7
- clearTimeout(ref.current)
8
- ref.current = -1
9
- }, [])
10
-
11
- const start = useCallback(() => {
12
- stop()
13
- ref.current = setTimeout(handler, timeout)
14
- }, [handler, timeout, stop])
15
-
16
- useEffect(() => stop, [stop])
17
-
18
- return [start, stop]
19
- }
20
-
21
- export default useTimeout
@@ -1,56 +0,0 @@
1
- import { useCallback, useEffect, useRef } from 'react'
2
- import { Vocal as SpeechRecognitionWrapper } from '@untemps/vocal'
3
-
4
- const useVocal = (lang = 'en-US', grammars = null, __rsInstance = null) => {
5
- const ref = useRef(null)
6
-
7
- useEffect(() => {
8
- if (SpeechRecognitionWrapper.isSupported) {
9
- ref.current = __rsInstance || new SpeechRecognitionWrapper({ lang, grammars })
10
- return () => {
11
- ref.current.abort()
12
- ref.current.cleanup()
13
- }
14
- }
15
- }, [lang, grammars, __rsInstance])
16
-
17
- const start = useCallback(() => {
18
- if (ref.current) {
19
- ref.current.start()
20
- }
21
- }, [])
22
-
23
- const stop = useCallback(() => {
24
- if (ref.current) {
25
- ref.current.stop()
26
- }
27
- }, [])
28
-
29
- const abort = useCallback(() => {
30
- if (ref.current) {
31
- ref.current.abort()
32
- }
33
- }, [])
34
-
35
- const subscribe = useCallback((eventType, handler) => {
36
- if (ref.current) {
37
- ref.current.addEventListener(eventType, handler)
38
- }
39
- }, [])
40
-
41
- const unsubscribe = useCallback((eventType, handler) => {
42
- if (ref.current) {
43
- ref.current.removeEventListener(eventType, handler)
44
- }
45
- }, [])
46
-
47
- const clean = useCallback(() => {
48
- if (ref.current) {
49
- ref.current.cleanup()
50
- }
51
- }, [])
52
-
53
- return [ref, { start, stop, abort, subscribe, unsubscribe, clean }]
54
- }
55
-
56
- export default useVocal
package/src/index.js DELETED
@@ -1,7 +0,0 @@
1
- import Vocal from './components/Vocal'
2
- import { Vocal as SpeechRecognitionWrapper } from '@untemps/vocal'
3
-
4
- export { default as useVocal } from './hooks/useVocal'
5
- export const isSupported = SpeechRecognitionWrapper.isSupported
6
-
7
- export default Vocal
package/vite.config.js DELETED
@@ -1,35 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- build: {
7
- lib: {
8
- entry: 'src/index.js',
9
- name: 'ReactVocal',
10
- formats: ['es', 'cjs', 'umd'],
11
- fileName: (format) => ({ es: 'index.es.js', umd: 'index.umd.js', cjs: 'index.js' })[format],
12
- },
13
- rollupOptions: {
14
- external: ['react', 'react-dom'],
15
- output: {
16
- globals: {
17
- react: 'React',
18
- 'react-dom': 'ReactDOM',
19
- },
20
- },
21
- },
22
- sourcemap: true,
23
- },
24
- test: {
25
- globals: true,
26
- environment: 'jsdom',
27
- setupFiles: ['./vitest.setup.js'],
28
- restoreMocks: true,
29
- coverage: {
30
- provider: 'v8',
31
- reporter: ['text', 'lcov'],
32
- reportsDirectory: './coverage',
33
- },
34
- },
35
- })
package/vitest.setup.js DELETED
@@ -1,71 +0,0 @@
1
- import { vi } from 'vitest'
2
- import '@testing-library/jest-dom/vitest'
3
-
4
- Object.defineProperty(global, 'navigator', {
5
- value: { userAgent: 'node.js' },
6
- writable: true,
7
- configurable: true,
8
- })
9
- global.PermissionStatus = vi.fn(function () {
10
- return {
11
- state: 'granted',
12
- addEventListener: vi.fn(),
13
- }
14
- })
15
- global.Permissions = vi.fn(function () {
16
- return {
17
- query: vi.fn().mockResolvedValue(new PermissionStatus()),
18
- }
19
- })
20
- Object.defineProperty(global.navigator, 'permissions', {
21
- value: new Permissions(),
22
- writable: true,
23
- configurable: true,
24
- })
25
- global.MediaDevices = vi.fn(function () {
26
- return {
27
- getUserMedia: vi.fn().mockResolvedValue('foo'),
28
- }
29
- })
30
- Object.defineProperty(global.navigator, 'mediaDevices', {
31
- value: new MediaDevices(),
32
- writable: true,
33
- configurable: true,
34
- })
35
- global.SpeechGrammarList = vi.fn(function () {
36
- return {
37
- length: 0,
38
- }
39
- })
40
- global.SpeechRecognition = vi.fn(function () {
41
- const handlers = {}
42
- return {
43
- addEventListener: vi.fn(function (type, callback) {
44
- handlers[type] = callback
45
- }),
46
- removeEventListener: vi.fn(),
47
- dispatchEvent: vi.fn(),
48
- start: vi.fn(function () {
49
- handlers.start?.()
50
- }),
51
- stop: vi.fn(function () {
52
- handlers.end?.()
53
- }),
54
- abort: vi.fn(function () {
55
- handlers.end?.()
56
- }),
57
- say: vi.fn(function (sentence) {
58
- handlers.speechstart?.()
59
-
60
- const resultEvent = new Event('result')
61
- resultEvent.resultIndex = 0
62
- resultEvent.results = [[{ transcript: sentence }]]
63
- handlers.speechend?.()
64
- if (sentence) {
65
- handlers.result?.(resultEvent)
66
- } else {
67
- handlers.nomatch?.()
68
- }
69
- }),
70
- }
71
- })