@corti/dictation-web 0.0.0-rc.359 → 0.0.0-test.571

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 (223) hide show
  1. package/README.md +163 -102
  2. package/dist/CortiDictation.d.ts +6 -2
  3. package/dist/CortiDictation.js +36 -14
  4. package/dist/CortiDictation.js.map +1 -1
  5. package/dist/bundle.js +3888 -1787
  6. package/dist/components/audio-visualiser.d.ts +5 -3
  7. package/dist/components/audio-visualiser.js +38 -46
  8. package/dist/components/audio-visualiser.js.map +1 -1
  9. package/dist/components/corti-dictation.d.ts +136 -0
  10. package/dist/components/corti-dictation.js +273 -0
  11. package/dist/components/corti-dictation.js.map +1 -0
  12. package/dist/components/device-selector.d.ts +14 -0
  13. package/dist/components/device-selector.js +75 -0
  14. package/dist/components/device-selector.js.map +1 -0
  15. package/dist/components/keybinding-selector.d.ts +14 -0
  16. package/dist/components/keybinding-selector.js +81 -0
  17. package/dist/components/keybinding-selector.js.map +1 -0
  18. package/dist/components/language-selector.d.ts +15 -0
  19. package/dist/components/language-selector.js +74 -0
  20. package/dist/components/language-selector.js.map +1 -0
  21. package/dist/components/mode-selector.d.ts +14 -0
  22. package/dist/components/mode-selector.js +73 -0
  23. package/dist/components/mode-selector.js.map +1 -0
  24. package/dist/components/recording-button.d.ts +31 -0
  25. package/dist/components/recording-button.js +262 -0
  26. package/dist/components/recording-button.js.map +1 -0
  27. package/dist/components/settings-menu.d.ts +12 -14
  28. package/dist/components/settings-menu.js +68 -153
  29. package/dist/components/settings-menu.js.map +1 -1
  30. package/dist/constants.d.ts +8 -2
  31. package/dist/constants.js +38 -12
  32. package/dist/constants.js.map +1 -1
  33. package/dist/contexts/dictation-context.d.ts +107 -0
  34. package/dist/contexts/dictation-context.js +290 -0
  35. package/dist/contexts/dictation-context.js.map +1 -0
  36. package/dist/controllers/DictationController.d.ts +35 -0
  37. package/dist/controllers/DictationController.js +130 -0
  38. package/dist/controllers/DictationController.js.map +1 -0
  39. package/dist/controllers/MediaController.d.ts +31 -0
  40. package/dist/controllers/MediaController.js +99 -0
  41. package/dist/controllers/MediaController.js.map +1 -0
  42. package/dist/controllers/devices-controller.d.ts +26 -0
  43. package/dist/controllers/devices-controller.js +99 -0
  44. package/dist/controllers/devices-controller.js.map +1 -0
  45. package/dist/controllers/dictation-controller.d.ts +29 -0
  46. package/dist/controllers/dictation-controller.js +179 -0
  47. package/dist/controllers/dictation-controller.js.map +1 -0
  48. package/dist/controllers/keybinding-controller.d.ts +17 -0
  49. package/dist/controllers/keybinding-controller.js +80 -0
  50. package/dist/controllers/keybinding-controller.js.map +1 -0
  51. package/dist/controllers/languages-controller.d.ts +26 -0
  52. package/dist/controllers/languages-controller.js +83 -0
  53. package/dist/controllers/languages-controller.js.map +1 -0
  54. package/dist/controllers/media-controller.d.ts +24 -0
  55. package/dist/controllers/media-controller.js +115 -0
  56. package/dist/controllers/media-controller.js.map +1 -0
  57. package/dist/index.d.ts +11 -1
  58. package/dist/index.js +39 -3
  59. package/dist/index.js.map +1 -1
  60. package/dist/package.json +14 -0
  61. package/dist/src/components/audio-visualiser.d.ts +14 -0
  62. package/dist/src/components/audio-visualiser.js +57 -0
  63. package/dist/src/components/audio-visualiser.js.map +1 -0
  64. package/dist/src/components/corti-dictation.d.ts +123 -0
  65. package/dist/src/components/corti-dictation.js +224 -0
  66. package/dist/src/components/corti-dictation.js.map +1 -0
  67. package/dist/src/components/device-selector.d.ts +24 -0
  68. package/dist/src/components/device-selector.js +106 -0
  69. package/dist/src/components/device-selector.js.map +1 -0
  70. package/dist/src/components/language-selector.d.ts +24 -0
  71. package/dist/src/components/language-selector.js +100 -0
  72. package/dist/src/components/language-selector.js.map +1 -0
  73. package/dist/src/components/recording-button.d.ts +37 -0
  74. package/dist/src/components/recording-button.js +203 -0
  75. package/dist/src/components/recording-button.js.map +1 -0
  76. package/dist/src/components/settings-menu.d.ts +16 -0
  77. package/dist/src/components/settings-menu.js +80 -0
  78. package/dist/src/components/settings-menu.js.map +1 -0
  79. package/dist/src/constants.d.ts +4 -0
  80. package/dist/src/constants.js +37 -0
  81. package/dist/src/constants.js.map +1 -0
  82. package/dist/src/contexts/dictation-context.d.ts +97 -0
  83. package/dist/src/contexts/dictation-context.js +208 -0
  84. package/dist/src/contexts/dictation-context.js.map +1 -0
  85. package/dist/src/controllers/DictationController.d.ts +35 -0
  86. package/dist/src/controllers/DictationController.js +130 -0
  87. package/dist/src/controllers/DictationController.js.map +1 -0
  88. package/dist/src/controllers/MediaController.d.ts +31 -0
  89. package/dist/src/controllers/MediaController.js +99 -0
  90. package/dist/src/controllers/MediaController.js.map +1 -0
  91. package/dist/src/icons/icons.d.ts +17 -0
  92. package/dist/src/icons/icons.js +158 -0
  93. package/dist/src/icons/icons.js.map +1 -0
  94. package/dist/src/styles/ComponentStyles.d.ts +2 -0
  95. package/dist/src/styles/ComponentStyles.js +18 -0
  96. package/dist/src/styles/ComponentStyles.js.map +1 -0
  97. package/dist/src/styles/audio-visualiser.d.ts +2 -0
  98. package/dist/src/styles/audio-visualiser.js +33 -0
  99. package/dist/src/styles/audio-visualiser.js.map +1 -0
  100. package/dist/src/styles/buttons.d.ts +2 -0
  101. package/dist/src/styles/buttons.js +52 -0
  102. package/dist/src/styles/buttons.js.map +1 -0
  103. package/dist/src/styles/callout.d.ts +2 -0
  104. package/dist/src/styles/callout.js +23 -0
  105. package/dist/src/styles/callout.js.map +1 -0
  106. package/dist/src/styles/default-theme.d.ts +2 -0
  107. package/dist/src/styles/default-theme.js +50 -0
  108. package/dist/src/styles/default-theme.js.map +1 -0
  109. package/dist/src/styles/recording-button.d.ts +2 -0
  110. package/dist/src/styles/recording-button.js +8 -0
  111. package/dist/src/styles/recording-button.js.map +1 -0
  112. package/dist/src/styles/select.d.ts +2 -0
  113. package/dist/src/styles/select.js +36 -0
  114. package/dist/src/styles/select.js.map +1 -0
  115. package/dist/src/styles/settings-menu.d.ts +2 -0
  116. package/dist/src/styles/settings-menu.js +34 -0
  117. package/dist/src/styles/settings-menu.js.map +1 -0
  118. package/dist/src/types.d.ts +7 -0
  119. package/dist/src/types.js +2 -0
  120. package/dist/src/types.js.map +1 -0
  121. package/dist/src/utils/auth.d.ts +9 -0
  122. package/dist/src/utils/auth.js +21 -0
  123. package/dist/src/utils/auth.js.map +1 -0
  124. package/dist/src/utils/converters.d.ts +4 -0
  125. package/dist/src/utils/converters.js +8 -0
  126. package/dist/src/utils/converters.js.map +1 -0
  127. package/dist/src/utils/devices.d.ts +26 -0
  128. package/dist/src/utils/devices.js +53 -0
  129. package/dist/src/utils/devices.js.map +1 -0
  130. package/dist/src/utils/events.d.ts +44 -0
  131. package/dist/src/utils/events.js +88 -0
  132. package/dist/src/utils/events.js.map +1 -0
  133. package/dist/src/utils/languages.d.ts +7 -0
  134. package/dist/src/utils/languages.js +29 -0
  135. package/dist/src/utils/languages.js.map +1 -0
  136. package/dist/src/utils/media.d.ts +6 -0
  137. package/dist/src/utils/media.js +39 -0
  138. package/dist/src/utils/media.js.map +1 -0
  139. package/dist/src/utils/token.d.ts +13 -0
  140. package/dist/src/utils/token.js +60 -0
  141. package/dist/src/utils/token.js.map +1 -0
  142. package/dist/src/utils/validation.d.ts +1 -0
  143. package/dist/src/utils/validation.js +7 -0
  144. package/dist/src/utils/validation.js.map +1 -0
  145. package/dist/stories/audio-visualiser.stories.d.ts +39 -0
  146. package/dist/stories/audio-visualiser.stories.js +71 -0
  147. package/dist/stories/audio-visualiser.stories.js.map +1 -0
  148. package/dist/stories/corti-dictation.stories.d.ts +27 -0
  149. package/dist/stories/corti-dictation.stories.js +129 -0
  150. package/dist/stories/corti-dictation.stories.js.map +1 -0
  151. package/dist/stories/device-selector.stories.d.ts +18 -0
  152. package/dist/stories/device-selector.stories.js +84 -0
  153. package/dist/stories/device-selector.stories.js.map +1 -0
  154. package/dist/stories/language-selector.stories.d.ts +18 -0
  155. package/dist/stories/language-selector.stories.js +53 -0
  156. package/dist/stories/language-selector.stories.js.map +1 -0
  157. package/dist/stories/recording-button.stories.d.ts +27 -0
  158. package/dist/stories/recording-button.stories.js +90 -0
  159. package/dist/stories/recording-button.stories.js.map +1 -0
  160. package/dist/stories/settings-menu.stories.d.ts +23 -0
  161. package/dist/stories/settings-menu.stories.js +156 -0
  162. package/dist/stories/settings-menu.stories.js.map +1 -0
  163. package/dist/styles/ComponentStyles.js +6 -41
  164. package/dist/styles/ComponentStyles.js.map +1 -1
  165. package/dist/styles/audio-visualiser.d.ts +2 -0
  166. package/dist/styles/audio-visualiser.js +33 -0
  167. package/dist/styles/audio-visualiser.js.map +1 -0
  168. package/dist/styles/buttons.js +19 -26
  169. package/dist/styles/buttons.js.map +1 -1
  170. package/dist/styles/callout.js +7 -17
  171. package/dist/styles/callout.js.map +1 -1
  172. package/dist/styles/component-styles.d.ts +3 -0
  173. package/dist/styles/component-styles.js +32 -0
  174. package/dist/styles/component-styles.js.map +1 -0
  175. package/dist/styles/default-theme.d.ts +2 -0
  176. package/dist/styles/default-theme.js +14 -0
  177. package/dist/styles/default-theme.js.map +1 -0
  178. package/dist/styles/keybinding-selector.d.ts +2 -0
  179. package/dist/styles/keybinding-selector.js +72 -0
  180. package/dist/styles/keybinding-selector.js.map +1 -0
  181. package/dist/styles/mode-selector.d.ts +2 -0
  182. package/dist/styles/mode-selector.js +54 -0
  183. package/dist/styles/mode-selector.js.map +1 -0
  184. package/dist/styles/recording-button.d.ts +2 -0
  185. package/dist/styles/recording-button.js +8 -0
  186. package/dist/styles/recording-button.js.map +1 -0
  187. package/dist/styles/select.d.ts +1 -1
  188. package/dist/styles/select.js +14 -18
  189. package/dist/styles/select.js.map +1 -1
  190. package/dist/styles/settings-menu.d.ts +2 -0
  191. package/dist/styles/settings-menu.js +42 -0
  192. package/dist/styles/settings-menu.js.map +1 -0
  193. package/dist/tsconfig.stories.tsbuildinfo +1 -0
  194. package/dist/types.d.ts +9 -8
  195. package/dist/types.js.map +1 -1
  196. package/dist/utils/auth.d.ts +9 -0
  197. package/dist/utils/auth.js +21 -0
  198. package/dist/utils/auth.js.map +1 -0
  199. package/dist/utils/converters.d.ts +4 -0
  200. package/dist/utils/converters.js +8 -0
  201. package/dist/utils/converters.js.map +1 -0
  202. package/dist/utils/devices.d.ts +26 -0
  203. package/dist/utils/devices.js +53 -0
  204. package/dist/utils/devices.js.map +1 -0
  205. package/dist/utils/events.d.ts +53 -0
  206. package/dist/utils/events.js +102 -0
  207. package/dist/utils/events.js.map +1 -0
  208. package/dist/utils/keybinding.d.ts +49 -0
  209. package/dist/utils/keybinding.js +140 -0
  210. package/dist/utils/keybinding.js.map +1 -0
  211. package/dist/utils/languages.d.ts +8 -0
  212. package/dist/utils/languages.js +29 -0
  213. package/dist/utils/languages.js.map +1 -0
  214. package/dist/utils/media.d.ts +6 -0
  215. package/dist/utils/media.js +39 -0
  216. package/dist/utils/media.js.map +1 -0
  217. package/dist/utils/token.d.ts +13 -0
  218. package/dist/utils/token.js +60 -0
  219. package/dist/utils/token.js.map +1 -0
  220. package/dist/utils/validation.d.ts +1 -0
  221. package/dist/utils/validation.js +7 -0
  222. package/dist/utils/validation.js.map +1 -0
  223. package/package.json +29 -55
package/README.md CHANGED
@@ -1,156 +1,217 @@
1
1
  # Corti Dictation Web Component
2
2
 
3
+ [![Published on npm](https://img.shields.io/npm/v/@corti/dictation-web.svg?logo=npm)](https://www.npmjs.com/package/@corti/dictation-web)
4
+ [![License: MIT](https://img.shields.io/npm/l/%40corti%2Fdictation-web)](https://opensource.org/licenses/MIT)
5
+ [![Get Support on Discord](https://img.shields.io/badge/Discord-Get%20Support-5865F2.svg?logo=discord&logoColor=fff)](https://discord.com/invite/zXeXHgnZXX)
6
+ [![Live Demo](https://img.shields.io/badge/Live%20Demo-blue.svg?logo=rocket&logoColor=fff)](https://codepen.io/hccullen/pen/OPJmxQR)
7
+
3
8
  ## Overview
4
9
 
5
10
  The **Corti Dictation Web Component** is a web component that enables real-time speech-to-text dictation using Corti's Dictation API. It provides a simple interface for capturing audio, streaming it to the API, and handling transcripts.
6
11
 
7
- > **Note:** OAuth 2.0 authentication is not handled by this library. The client must provide an API key or authorization token before using the component.
12
+ This library offers two approaches:
13
+ - **Opinionated Component**: Use `<corti-dictation>` for a complete, ready-to-use solution with built-in UI
14
+ - **Modular Components**: Use individual components for maximum flexibility and custom UI implementations
15
+
16
+ > **Note:** OAuth 2.0 authentication is not handled by this library. The client must provide an authorization token or token refresh function while using the component.
17
+
18
+ ## Component Architecture
19
+
20
+ ### Opinionated Component
21
+
22
+ **`<corti-dictation>`** - A complete, ready-to-use component that includes:
23
+ - Recording button with visual feedback
24
+ - Settings menu for device, language, mode, and keybinding selection
25
+ - Automatic state management
26
+ - Built-in styling and theming
27
+ - Support for toggle-to-talk and push-to-talk modes
28
+ - Keyboard shortcut (keybinding) support
29
+
30
+ This is the easiest way to get started and works out of the box.
31
+
32
+ ### Modular Components
33
+
34
+ For more control and flexibility, you can use individual components:
35
+
36
+ - **`<dictation-root>`** - Context provider that manages authentication, configuration, and shared state
37
+ - **`<dictation-recording-button>`** - Standalone recording button with audio visualization
38
+ - **`<dictation-settings-menu>`** - Settings menu with device, language, mode, and keybinding selectors
39
+ - **`<dictation-device-selector>`** - Device selection dropdown
40
+ - **`<dictation-language-selector>`** - Language selection dropdown
41
+ - **`<dictation-mode-selector>`** - Mode selection component (toggle-to-talk or push-to-talk)
42
+ - **`<dictation-keybinding-selector>`** - Keybinding configuration component for keyboard shortcuts
43
+
44
+ These components share state through a context system, allowing you to build custom UIs while leveraging the same underlying functionality.
8
45
 
9
46
  ## Installation
10
47
 
11
- Include the Web Component in your project by importing the JavaScript module:
48
+ Install the package using your preferred package manager:
12
49
 
13
- ```html
50
+ ```bash
51
+ # npm
14
52
  npm i @corti/dictation-web
53
+
54
+ # yarn
55
+ yarn add @corti/dictation-web
56
+
57
+ # pnpm
58
+ pnpm add @corti/dictation-web
59
+
60
+ # bun
61
+ bun add @corti/dictation-web
15
62
  ```
16
63
 
17
- Then import the module like so:
64
+ Then import the module in your code. You can either use a side-effect import to auto-register the component:
18
65
 
19
66
  ```js
20
- // Import the Corti Dictation Web Component
67
+ // Side-effect import - automatically registers the component
21
68
  import '@corti/dictation-web';
22
69
  ```
23
70
 
24
- Alternatively, use a CDN to start quickly (not recommended).
71
+ Or import the component class directly:
72
+
73
+ ```js
74
+ // Named import - register the component manually if needed
75
+ import { CortiDictation } from '@corti/dictation-web';
76
+ ```
77
+
78
+ Alternatively, use a CDN to start quickly (not recommended for production):
25
79
 
26
80
  ```html
27
81
  <script
28
- src="https://cdn.jsdelivr.net/npm/@corti/dictation-web/dist/bundle.min.js"
29
- preload
82
+ src="https://cdn.jsdelivr.net/npm/@corti/dictation-web/dist/bundle.js"
30
83
  type="module"
31
84
  ></script>
32
85
  ```
33
86
 
34
- ## Usage
35
-
36
- ### Demo
87
+ ## Demo
37
88
 
38
89
  🚀 [Hosted Demo](https://codepen.io/hccullen/pen/OPJmxQR)
39
90
 
40
- ### Basic Example
91
+ ## Quick Start
92
+
93
+ Here's a simple example to get you started:
41
94
 
42
95
  ```html
43
96
  <!DOCTYPE html>
44
97
  <html lang="en">
45
- <body>
46
- <corti-dictation id="dictation"></corti-dictation>
47
- <textarea
48
- id="transcript"
49
- placeholder="Transcript will appear here..."
50
- ></textarea>
51
-
52
- <script>
53
- import '@corti/dictation-web';
54
- const dictationEl = document.getElementById('dictation');
55
- dictationEl.addEventListener('ready', () => {
56
- dictationEl.setAccessToken('YOUR_AUTH_TOKEN'); // Note: Never hardcode tokens
57
- });
58
- dictationEl.addEventListener('transcript', e => {
59
- document.getElementById('transcript').value += e.detail.data.text + ' ';
60
- });
61
- </script>
62
- </body>
98
+ <body>
99
+ <corti-dictation id="dictation"></corti-dictation>
100
+ <textarea
101
+ id="transcript"
102
+ placeholder="Transcript will appear here..."
103
+ ></textarea>
104
+
105
+ <script type="module">
106
+ import '@corti/dictation-web';
107
+
108
+ const dictationEl = document.getElementById('dictation');
109
+ const transcriptEl = document.getElementById('transcript');
110
+
111
+ dictationEl.addEventListener('ready', () => {
112
+ dictationEl.accessToken = 'YOUR_AUTH_TOKEN'; // Note: Never hardcode tokens
113
+ });
114
+
115
+ dictationEl.addEventListener('transcript', (e) => {
116
+ if (e.detail.data.isFinal) {
117
+ transcriptEl.value += e.detail.data.text + ' ';
118
+ }
119
+ });
120
+ </script>
121
+ </body>
63
122
  </html>
64
123
  ```
65
124
 
66
- ## API Reference
67
-
68
- ### Properties
125
+ ### Modular Example
69
126
 
70
- | Property | Type | Description |
71
- | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
72
- | `devices` | Array | List of available recording devices. |
73
- | `selectedDevice` | Object | The selected device used for recording (MediaDeviceInfo). |
74
- | `recordingState` | String | Current state of recording (`stopped`, `recording`, `initializing` and `stopping`, ). |
75
- | `dictationConfig` | Object | Configuration settings for dictation. |
76
- | `languagesSupported` | String[] | List of all language codes available for use with the Web Component. |
77
- | `debug_displayAudio` | Boolean | Overrides any device selection and instead uses getDisplayMedia to stream system audio. Should only be used for debugging |
127
+ For more control, use individual components to build a custom UI:
78
128
 
79
- ### Methods
80
-
81
- | Method | Description |
82
- | -------------------------------------- | ---------------------------------------------------------------- |
83
- | `toggleRecording()` | Starts or stops recording. |
84
- | `setAccessToken(access_token: string)` | Set the latest access token. This will return the server config. |
85
- | `setAuthConfig(config: AuthConfig)` | Set authentication configuration with optional refresh mechanism. |
86
-
87
- ### Events
129
+ ```html
130
+ <!DOCTYPE html>
131
+ <html lang="en">
132
+ <body>
133
+ <dictation-root id="dictationRoot">
134
+ <dictation-recording-button></dictation-recording-button>
135
+ <dictation-settings-menu settingsEnabled="device,language,mode,keybinding"></dictation-settings-menu>
136
+ </dictation-root>
137
+
138
+ <textarea
139
+ id="transcript"
140
+ placeholder="Transcript will appear here..."
141
+ ></textarea>
142
+
143
+ <script type="module">
144
+ import '@corti/dictation-web';
145
+
146
+ const root = document.getElementById('dictationRoot');
147
+ const transcriptEl = document.getElementById('transcript');
148
+
149
+ root.addEventListener('ready', () => {
150
+ root.accessToken = 'YOUR_AUTH_TOKEN'; // Note: Never hardcode tokens
151
+ });
152
+
153
+ root.addEventListener('transcript', (e) => {
154
+ if (e.detail.data.isFinal) {
155
+ transcriptEl.value += e.detail.data.text + ' ';
156
+ }
157
+ });
158
+ </script>
159
+ </body>
160
+ </html>
161
+ ```
88
162
 
89
- | Event | Description |
90
- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
91
- | `ready` | Fired once the component is ready. |
92
- | `recording-state-changed` | Fired when the recording state changes. `detail.state` contains the new state. |
93
- | `recording-devices-changed` | Fired when the user switches recording devices or the list of recording devices changes. `detail.devices` contains the full devices list. `detail.selectedDevice` contains the current selected device. |
94
- | `transcript` | Fired when a new transcript is received. `detail.data.text` contains the transcribed text. |
95
- | `command` | Fired whenever a new command is detected. |
96
- | `audio-level-changed` | Fired when the input audio level changes. `detail.audioLevel` contains the new level. |
97
- | `usage` | Fired when usage information is received from the server. `detail.credits` contains the usage data. |
98
- | `stream-closed` | Fired when the WebSocket stream is closed. `detail` contains the close event data. |
99
- | `error` | Fired on error. `detail` contains the full error. |
163
+ ### Dictation Modes
100
164
 
101
- ## Authentication
165
+ The component supports two dictation modes:
102
166
 
103
- This library supports multiple authentication methods:
167
+ **Toggle-to-Talk (default):**
168
+ - Click or tap the recording button to start recording
169
+ - Click or tap again to stop recording
170
+ - Press the keybinding to toggle recording state
104
171
 
105
- ### Basic Bearer Token
106
- ```javascript
107
- dictation.setAccessToken('YOUR_JWT_TOKEN');
172
+ ```html
173
+ <corti-dictation mode="toggle-to-talk"></corti-dictation>
108
174
  ```
109
175
 
110
- ### With Refresh Token Support
111
-
112
- The library can automatically refresh tokens when they expire:
113
-
114
- ```javascript
115
- dictation.setAuthConfig({
116
- // This function runs before any API call when the access_token is near expiration
117
- refreshAccessToken: async (refreshToken?: string) => {
118
- // Custom refresh logic -- get new access_token from server
119
- // if accessToken is not passed to AuthConfig, refreshToken will be `undefined` for the first call,
120
- // then it will be the refreshToken returned from the previous token request
121
- const response = await fetch("https://your-auth-server/token", {
122
- method: "POST",
123
- headers: { "Content-Type": "application/json" },
124
- body: JSON.stringify({ refreshToken }),
125
- });
126
-
127
- const result = await response.json();
128
-
129
- // Return in the expected format
130
- return {
131
- accessToken: result.accessToken,
132
- refreshToken: result.refreshToken,
133
- };
134
- }
135
- });
176
+ **Push-to-Talk:**
177
+ - Press and hold the recording button to record
178
+ - Release to stop recording
179
+ - Press and hold the keybinding to record (keydown starts, keyup stops)
180
+
181
+ ```html
182
+ <corti-dictation mode="push-to-talk"></corti-dictation>
136
183
  ```
137
184
 
138
- The refresh mechanism automatically handles token renewal when the access token is near expiration, ensuring uninterrupted dictation sessions.
185
+ ### Keyboard Shortcuts (Keybindings)
139
186
 
140
- ## Usage Examples
187
+ Configure keyboard shortcuts to start/stop recording. You can use either key names (from `event.key`) or key codes (from `event.code`):
141
188
 
142
- Explore practical implementations and usage examples in the [Demo Folder](https://github.com/corticph/dictation-web-sdk/tree/main/demo). These demos can also be run locally.
189
+ ```html
190
+ <!-- Use backtick key (default) - key name -->
191
+ <corti-dictation keybinding="`"></corti-dictation>
143
192
 
144
- ## Styling
193
+ <!-- Use 'k' key - key name -->
194
+ <corti-dictation keybinding="k"></corti-dictation>
145
195
 
146
- ![UI Overview](https://github.com/corticph/dictation-web-sdk/blob/main/docs/ui.png)
196
+ <!-- Use Meta key (Cmd on Mac, Meta elsewhere) - key name -->
197
+ <corti-dictation keybinding="meta"></corti-dictation>
147
198
 
148
- The default UI is designed to be slotted into existing applications seamlessly, however, it also supports custom styling as well as theming. The UI can be fully customized using CSS properties. Refer to our [Styling Guide](https://github.com/corticph/dictation-web-sdk/blob/main/docs/styling.md) for detailed instructions.
199
+ <!-- Use key codes instead of key names -->
200
+ <corti-dictation keybinding="Backquote"></corti-dictation> <!-- backtick -->
201
+ <corti-dictation keybinding="KeyK"></corti-dictation> <!-- 'k' key -->
202
+ <corti-dictation keybinding="MetaLeft"></corti-dictation> <!-- Meta key -->
203
+ ```
149
204
 
150
- ## License
205
+ Keybindings are platform-aware:
206
+ - Keybindings are automatically ignored when typing in input fields, textareas, or contenteditable elements
207
+ - Both key names (e.g., `"k"`, `"Meta"`) and key codes (e.g., `"KeyK"`, `"MetaLeft"`) are supported
151
208
 
152
- This Web Component library is licensed under MIT.
209
+ ## Documentation
153
210
 
154
- ## Support
211
+ For more detailed information, see:
155
212
 
156
- For issues or questions, contact **Corti Support** at [support@corti.ai](mailto:help@corti.ai).
213
+ - **[API Reference](docs/API_REFERENCE.md)** - Complete API documentation for properties, methods, and events
214
+ - **[Authentication Guide](docs/AUTHENTICATION.md)** - How to set up authentication with tokens and refresh mechanisms
215
+ - **[Styling Guide](docs/styling.md)** - Customize the component's appearance with CSS variables and themes
216
+ - **[Examples](demo/README.md)** - Practical usage examples and demos
217
+ - **[Development Guide](docs/DEV_README.md)** - Information for contributors and developers
@@ -3,12 +3,14 @@ import { LitElement } from 'lit';
3
3
  import './components/settings-menu.js';
4
4
  import './components/audio-visualiser.js';
5
5
  import './icons/icons.js';
6
- import type { RecordingState, ServerConfig } from './types.js';
6
+ import type { ConfigurableSettings, RecordingState, ServerConfig } from './types.js';
7
7
  export declare class CortiDictation extends LitElement {
8
8
  static styles: import("lit").CSSResult[];
9
9
  dictationConfig: Corti.TranscribeConfig;
10
10
  languagesSupported: Corti.TranscribeSupportedLanguage[];
11
11
  debug_displayAudio: boolean;
12
+ settingsEnabled: ConfigurableSettings[];
13
+ preventButtonFocus: boolean;
12
14
  private _serverConfig;
13
15
  private _audioLevel;
14
16
  private _recordingState;
@@ -16,6 +18,8 @@ export declare class CortiDictation extends LitElement {
16
18
  private _devices;
17
19
  private recorderManager;
18
20
  connectedCallback(): Promise<void>;
21
+ startRecording(): void;
22
+ stopRecording(): void;
19
23
  toggleRecording(): void;
20
24
  /**
21
25
  * Sets the access token and returns the server configuration.
@@ -43,7 +47,7 @@ export declare class CortiDictation extends LitElement {
43
47
  get devices(): MediaDeviceInfo[];
44
48
  setRecordingDevice(device: MediaDeviceInfo): Promise<void>;
45
49
  setPrimaryLanguage(language: string): void;
46
- _toggleRecording(): void;
50
+ _onButtonMouseDown(event: MouseEvent): void;
47
51
  _onRecordingDevicesChanged(event: Event): Promise<void>;
48
52
  _onLanguageChanged(event: Event): void;
49
53
  render(): import("lit-html").TemplateResult<1>;
@@ -23,6 +23,8 @@ export class CortiDictation extends LitElement {
23
23
  this.dictationConfig = DEFAULT_DICTATION_CONFIG;
24
24
  this.languagesSupported = LANGUAGES_SUPPORTED;
25
25
  this.debug_displayAudio = false;
26
+ this.settingsEnabled = ["device", "language"];
27
+ this.preventButtonFocus = true;
26
28
  this._audioLevel = 0;
27
29
  this._recordingState = 'stopped';
28
30
  this._devices = [];
@@ -77,8 +79,25 @@ export class CortiDictation extends LitElement {
77
79
  });
78
80
  });
79
81
  }
82
+ startRecording() {
83
+ if (!this._serverConfig)
84
+ return;
85
+ this.recorderManager.startRecording({
86
+ dictationConfig: this.dictationConfig,
87
+ serverConfig: this._serverConfig,
88
+ debug_displayAudio: this.debug_displayAudio,
89
+ });
90
+ }
91
+ stopRecording() {
92
+ this.recorderManager.stopRecording();
93
+ }
80
94
  toggleRecording() {
81
- this._toggleRecording();
95
+ if (this._recordingState === 'recording') {
96
+ this.stopRecording();
97
+ }
98
+ else if (this._recordingState === 'stopped') {
99
+ this.startRecording();
100
+ }
82
101
  }
83
102
  /**
84
103
  * Sets the access token and returns the server configuration.
@@ -190,18 +209,11 @@ export class CortiDictation extends LitElement {
190
209
  }
191
210
  }
192
211
  }
193
- _toggleRecording() {
194
- if (!this._serverConfig)
195
- return;
196
- if (this._recordingState === 'recording') {
197
- this.recorderManager.stopRecording();
198
- }
199
- else if (this._recordingState === 'stopped') {
200
- this.recorderManager.startRecording({
201
- dictationConfig: this.dictationConfig,
202
- serverConfig: this._serverConfig,
203
- debug_displayAudio: this.debug_displayAudio,
204
- });
212
+ _onButtonMouseDown(event) {
213
+ // Prevent button from taking focus on mouse click
214
+ // This keeps focus on the textarea
215
+ if (this.preventButtonFocus) {
216
+ event.preventDefault();
205
217
  }
206
218
  }
207
219
  // Handle device change events if needed
@@ -227,7 +239,8 @@ export class CortiDictation extends LitElement {
227
239
  return html `
228
240
  <div class="wrapper">
229
241
  <button
230
- @click=${this._toggleRecording}
242
+ @click=${this.toggleRecording}
243
+ @mousedown=${this._onButtonMouseDown}
231
244
  class=${isRecording ? 'red' : 'accent'}
232
245
  >
233
246
  ${isLoading
@@ -241,13 +254,16 @@ export class CortiDictation extends LitElement {
241
254
  ></audio-visualiser>
242
255
  </button>
243
256
 
257
+ ${this.settingsEnabled.length > 0 ? html `
244
258
  <settings-menu
245
259
  .selectedDevice=${this._selectedDevice}
246
260
  .selectedLanguage=${this.dictationConfig.primaryLanguage}
247
261
  ?settingsDisabled=${this._recordingState !== 'stopped'}
248
262
  @recording-devices-changed=${this._onRecordingDevicesChanged}
249
263
  @language-changed=${this._onLanguageChanged}
264
+ .settingsEnabled=${this.settingsEnabled}
250
265
  ></settings-menu>
266
+ ` : ''}
251
267
  </div>
252
268
  `;
253
269
  }
@@ -262,6 +278,12 @@ __decorate([
262
278
  __decorate([
263
279
  property({ type: Boolean })
264
280
  ], CortiDictation.prototype, "debug_displayAudio", void 0);
281
+ __decorate([
282
+ property({ type: Array })
283
+ ], CortiDictation.prototype, "settingsEnabled", void 0);
284
+ __decorate([
285
+ property({ type: Boolean })
286
+ ], CortiDictation.prototype, "preventButtonFocus", void 0);
265
287
  __decorate([
266
288
  state()
267
289
  ], CortiDictation.prototype, "_serverConfig", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../src/CortiDictation.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Corti } from '@corti/sdk';\n\n// corti-dictation.ts\nimport { html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RecorderManager } from './RecorderManager.js';\nimport './components/settings-menu.js';\nimport './components/audio-visualiser.js';\nimport './icons/icons.js';\nimport ThemeStyles from './styles/theme.js';\nimport ButtonStyles from './styles/buttons.js';\nimport ComponentStyles from './styles/ComponentStyles.js';\n\nimport type { RecordingState, ServerConfig } from './types.js';\nimport { DEFAULT_DICTATION_CONFIG, LANGUAGES_SUPPORTED } from './constants.js';\nimport CalloutStyles from './styles/callout.js';\nimport { decodeToken } from './utils.js';\n\nexport class CortiDictation extends LitElement {\n static styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyles];\n\n @property({ type: Object })\n dictationConfig: Corti.TranscribeConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Array })\n languagesSupported: Corti.TranscribeSupportedLanguage[] = LANGUAGES_SUPPORTED;\n\n @property({ type: Boolean })\n debug_displayAudio: boolean = false;\n\n @state()\n private _serverConfig: ServerConfig | undefined;\n\n @state()\n private _audioLevel: number = 0;\n\n @state()\n private _recordingState: RecordingState = 'stopped';\n\n @state()\n private _selectedDevice: MediaDeviceInfo | undefined;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n private recorderManager = new RecorderManager();\n\n async connectedCallback() {\n super.connectedCallback();\n const devices = await this.recorderManager.initialize();\n if (devices.selectedDevice) {\n this._selectedDevice = this.recorderManager.selectedDevice;\n this._devices = this.recorderManager.devices;\n this.dispatchEvent(new CustomEvent('ready'));\n }\n\n // Map event names to any extra handling logic\n const eventHandlers: Record<string, (e: CustomEvent) => void> = {\n 'recording-state-changed': e => {\n this._recordingState = e.detail.state;\n },\n 'devices-changed': () => {\n this._devices = [...this.recorderManager.devices];\n this.requestUpdate();\n },\n 'audio-level-changed': e => {\n this._audioLevel = e.detail.audioLevel;\n this.requestUpdate();\n },\n };\n\n const eventsToRelay = [\n 'recording-state-changed',\n 'recording-devices-changed',\n 'audio-level-changed',\n 'error',\n 'transcript',\n 'command',\n 'ready',\n 'usage',\n 'stream-closed',\n ];\n\n eventsToRelay.forEach(eventName => {\n this.recorderManager.addEventListener(eventName, (e: Event) => {\n const customEvent = e as CustomEvent;\n // Perform any additional handling if defined\n if (eventHandlers[eventName]) {\n eventHandlers[eventName](customEvent);\n }\n // Re-dispatch the event from the component\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail: customEvent.detail,\n bubbles: eventName !== 'error',\n composed: true,\n }),\n );\n });\n });\n }\n\n public toggleRecording() {\n this._toggleRecording();\n }\n\n /**\n * Sets the access token and returns the server configuration.\n *\n * NOTE: We decode the token here only for backward compatibility in return values.\n * The SDK now handles token parsing internally, so this return value should be\n * reduced in the future to only include necessary fields.\n */\n public setAccessToken(token: string) {\n try {\n const decoded = decodeToken(token);\n this._serverConfig = decoded;\n return decoded;\n } catch (e) {\n throw new Error('Invalid token');\n }\n }\n\n /**\n * Sets the authentication configuration and returns the server configuration.\n *\n * NOTE: We decode tokens here only for backward compatibility in return values.\n * The SDK now handles token parsing internally, so this return value should be\n * reduced in the future to only include necessary fields.\n */\n public async setAuthConfig(\n config: Corti.BearerOptions,\n ): Promise<ServerConfig> {\n try {\n const initialToken =\n 'accessToken' in config\n ? { accessToken: config.accessToken, refreshToken: config.refreshToken }\n : await config.refreshAccessToken();\n\n if (\n !initialToken?.accessToken ||\n typeof initialToken.accessToken !== 'string'\n ) {\n throw new Error('Access token is required and must be a string');\n }\n\n // Decode tokens only for return value compatibility\n // The SDK handles its own token parsing internally\n const decoded = decodeToken(initialToken.accessToken);\n\n if (!decoded) {\n throw new Error('Invalid token format');\n }\n\n this._serverConfig = {\n environment: decoded.environment,\n tenant: decoded.tenant,\n accessToken: initialToken.accessToken,\n refreshToken: config.refreshToken,\n refreshAccessToken: async (refreshToken?: string) => {\n try {\n if (!config.refreshAccessToken) {\n return {\n accessToken: this._serverConfig?.accessToken || 'no_token',\n expiresIn: Infinity,\n refreshToken,\n };\n }\n\n const response = await config.refreshAccessToken(refreshToken);\n\n if (this._serverConfig) {\n this._serverConfig.accessToken = response.accessToken;\n this._serverConfig.refreshToken = response.refreshToken;\n }\n\n return response;\n } catch (e) {\n throw new Error('Error when refreshing access token');\n }\n },\n };\n\n return this._serverConfig;\n } catch (e) {\n throw new Error('Invalid config');\n }\n }\n\n public get selectedDevice(): MediaDeviceInfo | null {\n return this.recorderManager.selectedDevice || null;\n }\n\n public get recordingState(): RecordingState {\n return this._recordingState;\n }\n\n public get devices(): MediaDeviceInfo[] {\n return this._devices;\n }\n\n public async setRecordingDevice(device: MediaDeviceInfo) {\n this.recorderManager.selectedDevice = device;\n this._selectedDevice = device;\n if (!this._serverConfig) return;\n if (this._recordingState === 'recording') {\n await this.recorderManager.stopRecording();\n await this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n });\n }\n }\n\n public setPrimaryLanguage(language: string) {\n if (LANGUAGES_SUPPORTED.includes(language)) {\n this.dictationConfig = {\n ...this.dictationConfig,\n primaryLanguage: language,\n };\n\n // If recording is in progress, restart to apply the language change\n if (this._serverConfig && this._recordingState === 'recording') {\n this.recorderManager.stopRecording();\n this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n debug_displayAudio: this.debug_displayAudio,\n });\n }\n }\n }\n\n _toggleRecording() {\n if (!this._serverConfig) return;\n if (this._recordingState === 'recording') {\n this.recorderManager.stopRecording();\n } else if (this._recordingState === 'stopped') {\n this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n debug_displayAudio: this.debug_displayAudio,\n });\n }\n }\n\n // Handle device change events if needed\n async _onRecordingDevicesChanged(event: Event) {\n const customEvent = event as CustomEvent;\n this.setRecordingDevice(customEvent.detail.selectedDevice);\n }\n\n // Handle language change events\n _onLanguageChanged(event: Event) {\n const customEvent = event as CustomEvent;\n const language = customEvent.detail.language;\n if (language) {\n this.setPrimaryLanguage(language);\n }\n }\n\n render() {\n if (!this._serverConfig) {\n return html` <div style=\"display: none\"></div> `;\n }\n\n const isLoading =\n this._recordingState === 'initializing' ||\n this._recordingState === 'stopping';\n const isRecording = this._recordingState === 'recording';\n return html`\n <div class=\"wrapper\">\n <button\n @click=${this._toggleRecording}\n class=${isRecording ? 'red' : 'accent'}\n >\n ${isLoading\n ? html` <icon-loading-spinner></icon-loading-spinner>`\n : isRecording\n ? html` <icon-recording></icon-recording>`\n : html` <icon-mic-on></icon-mic-on>`}\n <audio-visualiser\n .level=${this._audioLevel}\n .active=${isRecording}\n ></audio-visualiser>\n </button>\n\n <settings-menu\n .selectedDevice=${this._selectedDevice}\n .selectedLanguage=${this.dictationConfig.primaryLanguage}\n ?settingsDisabled=${this._recordingState !== 'stopped'}\n @recording-devices-changed=${this._onRecordingDevicesChanged}\n @language-changed=${this._onLanguageChanged}\n ></settings-menu>\n </div>\n `;\n }\n}\n\nexport default CortiDictation;\n"]}
1
+ {"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../src/CortiDictation.ts"],"names":[],"mappings":";;;;;;AAEA,qBAAqB;AACrB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kBAAkB,CAAC;AAC1B,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAC5C,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,eAAe,MAAM,6BAA6B,CAAC;AAG1D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,OAAO,cAAe,SAAQ,UAAU;IAA9C;;QAIE,oBAAe,GAA2B,wBAAwB,CAAC;QAGnE,uBAAkB,GAAwC,mBAAmB,CAAC;QAG9E,uBAAkB,GAAY,KAAK,CAAC;QAGpC,oBAAe,GAA2B,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAGjE,uBAAkB,GAAY,IAAI,CAAC;QAM3B,gBAAW,GAAW,CAAC,CAAC;QAGxB,oBAAe,GAAmB,SAAS,CAAC;QAM5C,aAAQ,GAAsB,EAAE,CAAC;QAEjC,oBAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IA4QlD,CAAC;IA1QC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;YAC3D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;YAC7C,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,8CAA8C;QAC9C,MAAM,aAAa,GAA6C;YAC9D,yBAAyB,EAAE,CAAC,CAAC,EAAE;gBAC7B,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YACxC,CAAC;YACD,iBAAiB,EAAE,GAAG,EAAE;gBACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;gBAClD,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;YACD,qBAAqB,EAAE,CAAC,CAAC,EAAE;gBACzB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBACvC,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;SACF,CAAC;QAEF,MAAM,aAAa,GAAG;YACpB,yBAAyB;YACzB,2BAA2B;YAC3B,qBAAqB;YACrB,OAAO;YACP,YAAY;YACZ,SAAS;YACT,OAAO;YACP,OAAO;YACP,eAAe;SAChB,CAAC;QAEF,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YAChC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAQ,EAAE,EAAE;gBAC5D,MAAM,WAAW,GAAG,CAAgB,CAAC;gBACrC,6CAA6C;gBAC7C,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC7B,aAAa,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC;gBACxC,CAAC;gBACD,2CAA2C;gBAC3C,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;oBACzB,MAAM,EAAE,WAAW,CAAC,MAAM;oBAC1B,OAAO,EAAE,SAAS,KAAK,OAAO;oBAC9B,QAAQ,EAAE,IAAI;iBACf,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,cAAc;QACnB,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QAChC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;YAClC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,YAAY,EAAE,IAAI,CAAC,aAAc;YACjC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC5C,CAAC,CAAC;IACL,CAAC;IAEM,aAAa;QAClB,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC;IACvC,CAAC;IAEM,eAAe;QACpB,IAAI,IAAI,CAAC,eAAe,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;aAAM,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YAC9C,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,KAAa;QACjC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;YAC7B,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,aAAa,CACxB,MAA2B;QAE3B,IAAI,CAAC;YACH,MAAM,YAAY,GAChB,aAAa,IAAI,MAAM;gBACrB,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE;gBACxE,CAAC,CAAC,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAExC,IACE,CAAC,YAAY,EAAE,WAAW;gBAC1B,OAAO,YAAY,CAAC,WAAW,KAAK,QAAQ,EAC5C,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACnE,CAAC;YAED,oDAAoD;YACpD,mDAAmD;YACnD,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAEtD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,CAAC,aAAa,GAAG;gBACnB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,WAAW,EAAE,YAAY,CAAC,WAAW;gBACrC,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,kBAAkB,EAAE,KAAK,EAAE,YAAqB,EAAE,EAAE;oBAClD,IAAI,CAAC;wBACH,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;4BAC/B,OAAO;gCACL,WAAW,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,IAAI,UAAU;gCAC1D,SAAS,EAAE,QAAQ;gCACnB,YAAY;6BACb,CAAC;wBACJ,CAAC;wBAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;wBAE/D,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;4BACvB,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;4BACtD,IAAI,CAAC,aAAa,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;wBAC1D,CAAC;wBAED,OAAO,QAAQ,CAAC;oBAClB,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACX,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;oBACxD,CAAC;gBACH,CAAC;aACF,CAAC;YAEF,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,eAAe,CAAC,cAAc,IAAI,IAAI,CAAC;IACrD,CAAC;IAED,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEM,KAAK,CAAC,kBAAkB,CAAC,MAAuB;QACrD,IAAI,CAAC,eAAe,CAAC,cAAc,GAAG,MAAM,CAAC;QAC7C,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QAChC,IAAI,IAAI,CAAC,eAAe,KAAK,WAAW,EAAE,CAAC;YACzC,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;gBACxC,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,YAAY,EAAE,IAAI,CAAC,aAAa;aACjC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACxC,IAAI,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,eAAe,GAAG;gBACrB,GAAG,IAAI,CAAC,eAAe;gBACvB,eAAe,EAAE,QAAQ;aAC1B,CAAC;YAEF,oEAAoE;YACpE,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,eAAe,KAAK,WAAW,EAAE,CAAC;gBAC/D,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC;gBACrC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;oBAClC,eAAe,EAAE,IAAI,CAAC,eAAe;oBACrC,YAAY,EAAE,IAAI,CAAC,aAAa;oBAChC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;iBAC5C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,KAAiB;QAClC,kDAAkD;QAClD,mCAAmC;QACnC,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,KAAK,CAAC,0BAA0B,CAAC,KAAY;QAC3C,MAAM,WAAW,GAAG,KAAoB,CAAC;QACzC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,gCAAgC;IAChC,kBAAkB,CAAC,KAAY;QAC7B,MAAM,WAAW,GAAG,KAAoB,CAAC;QACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC7C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,IAAI,CAAA,qCAAqC,CAAC;QACnD,CAAC;QAED,MAAM,SAAS,GACb,IAAI,CAAC,eAAe,KAAK,cAAc;YACvC,IAAI,CAAC,eAAe,KAAK,UAAU,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,KAAK,WAAW,CAAC;QACzD,OAAO,IAAI,CAAA;;;mBAGI,IAAI,CAAC,eAAe;uBAChB,IAAI,CAAC,kBAAkB;kBAC5B,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;;YAEpC,SAAS;YACT,CAAC,CAAC,IAAI,CAAA,gDAAgD;YACtD,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,IAAI,CAAA,oCAAoC;gBAC1C,CAAC,CAAC,IAAI,CAAA,8BAA8B;;qBAE7B,IAAI,CAAC,WAAW;sBACf,WAAW;;;;UAIvB,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;;4BAEpB,IAAI,CAAC,eAAe;8BAClB,IAAI,CAAC,eAAe,CAAC,eAAe;8BACpC,IAAI,CAAC,eAAe,KAAK,SAAS;uCACzB,IAAI,CAAC,0BAA0B;8BACxC,IAAI,CAAC,kBAAkB;6BACxB,IAAI,CAAC,eAAe;;SAExC,CAAC,CAAC,CAAC,EAAE;;KAET,CAAC;IACJ,CAAC;;AA3SM,qBAAM,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,CAAC,AAA9D,CAA+D;AAG5E;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDACwC;AAGnE;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;0DACoD;AAG9E;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;0DACQ;AAGpC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;uDACuC;AAGjE;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;0DACO;AAG3B;IADP,KAAK,EAAE;qDACwC;AAGxC;IADP,KAAK,EAAE;mDACwB;AAGxB;IADP,KAAK,EAAE;uDAC4C;AAG5C;IADP,KAAK,EAAE;uDAC6C;AAG7C;IADP,KAAK,EAAE;gDACiC;AAgR3C,eAAe,cAAc,CAAC","sourcesContent":["import { type Corti } from '@corti/sdk';\n\n// corti-dictation.ts\nimport { html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RecorderManager } from './RecorderManager.js';\nimport './components/settings-menu.js';\nimport './components/audio-visualiser.js';\nimport './icons/icons.js';\nimport ThemeStyles from './styles/theme.js';\nimport ButtonStyles from './styles/buttons.js';\nimport ComponentStyles from './styles/ComponentStyles.js';\n\nimport type { ConfigurableSettings, RecordingState, ServerConfig } from './types.js';\nimport { DEFAULT_DICTATION_CONFIG, LANGUAGES_SUPPORTED } from './constants.js';\nimport CalloutStyles from './styles/callout.js';\nimport { decodeToken } from './utils.js';\n\nexport class CortiDictation extends LitElement {\n static styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyles];\n\n @property({ type: Object })\n dictationConfig: Corti.TranscribeConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Array })\n languagesSupported: Corti.TranscribeSupportedLanguage[] = LANGUAGES_SUPPORTED;\n\n @property({ type: Boolean })\n debug_displayAudio: boolean = false;\n\n @property({ type: Array })\n settingsEnabled: ConfigurableSettings[] = [\"device\", \"language\"];\n \n @property({ type: Boolean })\n preventButtonFocus: boolean = true;\n\n @state()\n private _serverConfig: ServerConfig | undefined;\n\n @state()\n private _audioLevel: number = 0;\n\n @state()\n private _recordingState: RecordingState = 'stopped';\n\n @state()\n private _selectedDevice: MediaDeviceInfo | undefined;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n private recorderManager = new RecorderManager();\n\n async connectedCallback() {\n super.connectedCallback();\n const devices = await this.recorderManager.initialize();\n if (devices.selectedDevice) {\n this._selectedDevice = this.recorderManager.selectedDevice;\n this._devices = this.recorderManager.devices;\n this.dispatchEvent(new CustomEvent('ready'));\n }\n\n // Map event names to any extra handling logic\n const eventHandlers: Record<string, (e: CustomEvent) => void> = {\n 'recording-state-changed': e => {\n this._recordingState = e.detail.state;\n },\n 'devices-changed': () => {\n this._devices = [...this.recorderManager.devices];\n this.requestUpdate();\n },\n 'audio-level-changed': e => {\n this._audioLevel = e.detail.audioLevel;\n this.requestUpdate();\n },\n };\n\n const eventsToRelay = [\n 'recording-state-changed',\n 'recording-devices-changed',\n 'audio-level-changed',\n 'error',\n 'transcript',\n 'command',\n 'ready',\n 'usage',\n 'stream-closed',\n ];\n\n eventsToRelay.forEach(eventName => {\n this.recorderManager.addEventListener(eventName, (e: Event) => {\n const customEvent = e as CustomEvent;\n // Perform any additional handling if defined\n if (eventHandlers[eventName]) {\n eventHandlers[eventName](customEvent);\n }\n // Re-dispatch the event from the component\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail: customEvent.detail,\n bubbles: eventName !== 'error',\n composed: true,\n }),\n );\n });\n });\n }\n\n public startRecording() {\n if (!this._serverConfig) return;\n this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig!,\n debug_displayAudio: this.debug_displayAudio,\n });\n }\n\n public stopRecording() {\n this.recorderManager.stopRecording();\n }\n\n public toggleRecording() {\n if (this._recordingState === 'recording') {\n this.stopRecording();\n } else if (this._recordingState === 'stopped') {\n this.startRecording();\n }\n }\n\n /**\n * Sets the access token and returns the server configuration.\n *\n * NOTE: We decode the token here only for backward compatibility in return values.\n * The SDK now handles token parsing internally, so this return value should be\n * reduced in the future to only include necessary fields.\n */\n public setAccessToken(token: string) {\n try {\n const decoded = decodeToken(token);\n this._serverConfig = decoded;\n return decoded;\n } catch (e) {\n throw new Error('Invalid token');\n }\n }\n\n /**\n * Sets the authentication configuration and returns the server configuration.\n *\n * NOTE: We decode tokens here only for backward compatibility in return values.\n * The SDK now handles token parsing internally, so this return value should be\n * reduced in the future to only include necessary fields.\n */\n public async setAuthConfig(\n config: Corti.BearerOptions,\n ): Promise<ServerConfig> {\n try {\n const initialToken =\n 'accessToken' in config\n ? { accessToken: config.accessToken, refreshToken: config.refreshToken }\n : await config.refreshAccessToken();\n\n if (\n !initialToken?.accessToken ||\n typeof initialToken.accessToken !== 'string'\n ) {\n throw new Error('Access token is required and must be a string');\n }\n\n // Decode tokens only for return value compatibility\n // The SDK handles its own token parsing internally\n const decoded = decodeToken(initialToken.accessToken);\n\n if (!decoded) {\n throw new Error('Invalid token format');\n }\n\n this._serverConfig = {\n environment: decoded.environment,\n tenant: decoded.tenant,\n accessToken: initialToken.accessToken,\n refreshToken: config.refreshToken,\n refreshAccessToken: async (refreshToken?: string) => {\n try {\n if (!config.refreshAccessToken) {\n return {\n accessToken: this._serverConfig?.accessToken || 'no_token',\n expiresIn: Infinity,\n refreshToken,\n };\n }\n\n const response = await config.refreshAccessToken(refreshToken);\n\n if (this._serverConfig) {\n this._serverConfig.accessToken = response.accessToken;\n this._serverConfig.refreshToken = response.refreshToken;\n }\n\n return response;\n } catch (e) {\n throw new Error('Error when refreshing access token');\n }\n },\n };\n\n return this._serverConfig;\n } catch (e) {\n throw new Error('Invalid config');\n }\n }\n\n public get selectedDevice(): MediaDeviceInfo | null {\n return this.recorderManager.selectedDevice || null;\n }\n\n public get recordingState(): RecordingState {\n return this._recordingState;\n }\n\n public get devices(): MediaDeviceInfo[] {\n return this._devices;\n }\n\n public async setRecordingDevice(device: MediaDeviceInfo) {\n this.recorderManager.selectedDevice = device;\n this._selectedDevice = device;\n if (!this._serverConfig) return;\n if (this._recordingState === 'recording') {\n await this.recorderManager.stopRecording();\n await this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n });\n }\n }\n\n public setPrimaryLanguage(language: string) {\n if (LANGUAGES_SUPPORTED.includes(language)) {\n this.dictationConfig = {\n ...this.dictationConfig,\n primaryLanguage: language,\n };\n\n // If recording is in progress, restart to apply the language change\n if (this._serverConfig && this._recordingState === 'recording') {\n this.recorderManager.stopRecording();\n this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n debug_displayAudio: this.debug_displayAudio,\n });\n }\n }\n }\n\n _onButtonMouseDown(event: MouseEvent) {\n // Prevent button from taking focus on mouse click\n // This keeps focus on the textarea\n if (this.preventButtonFocus) {\n event.preventDefault();\n }\n }\n\n // Handle device change events if needed\n async _onRecordingDevicesChanged(event: Event) {\n const customEvent = event as CustomEvent;\n this.setRecordingDevice(customEvent.detail.selectedDevice);\n }\n\n // Handle language change events\n _onLanguageChanged(event: Event) {\n const customEvent = event as CustomEvent;\n const language = customEvent.detail.language;\n if (language) {\n this.setPrimaryLanguage(language);\n }\n }\n\n render() {\n if (!this._serverConfig) {\n return html` <div style=\"display: none\"></div> `;\n }\n\n const isLoading =\n this._recordingState === 'initializing' ||\n this._recordingState === 'stopping';\n const isRecording = this._recordingState === 'recording';\n return html`\n <div class=\"wrapper\">\n <button\n @click=${this.toggleRecording}\n @mousedown=${this._onButtonMouseDown}\n class=${isRecording ? 'red' : 'accent'}\n >\n ${isLoading\n ? html` <icon-loading-spinner></icon-loading-spinner>`\n : isRecording\n ? html` <icon-recording></icon-recording>`\n : html` <icon-mic-on></icon-mic-on>`}\n <audio-visualiser\n .level=${this._audioLevel}\n .active=${isRecording}\n ></audio-visualiser>\n </button>\n\n ${this.settingsEnabled.length > 0 ? html`\n <settings-menu\n .selectedDevice=${this._selectedDevice}\n .selectedLanguage=${this.dictationConfig.primaryLanguage}\n ?settingsDisabled=${this._recordingState !== 'stopped'}\n @recording-devices-changed=${this._onRecordingDevicesChanged}\n @language-changed=${this._onLanguageChanged}\n .settingsEnabled=${this.settingsEnabled}\n ></settings-menu>\n ` : ''}\n </div>\n `;\n }\n}\n\nexport default CortiDictation;\n"]}