@corti/dictation-web 0.1.12 → 0.1.14

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/README.md CHANGED
@@ -1,116 +1,117 @@
1
- # Corti Dictation SDK
2
-
3
- ## Overview
4
-
5
- The **Corti Dictation SDK** 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
-
7
- > **Note:** OAuth 2.0 authentication is not handled by this SDK. The client must provide an API key or authorization token before using the component.
8
-
9
- ## Installation
10
-
11
- Include the SDK in your project by importing the JavaScript module:
12
-
13
- ```html
14
- npm i @corti/dictation-web
15
- ```
16
-
17
- Then import the module like so:
18
-
19
- ```js
20
- // Import the Corti Dictation SDK
21
- import '@corti/dictation-web';
22
- ```
23
-
24
- Alternatively, use a CDN to start quickly (not recommended).
25
-
26
- ```html
27
- <script
28
- src="https://cdn.jsdelivr.net/npm/@corti/dictation-web/dist/bundle.min.js"
29
- preload
30
- type="module"
31
- ></script>
32
- ```
33
-
34
- ## Usage
35
-
36
- ### Demo
37
-
38
- 🚀 [Hosted Demo](https://codepen.io/hccullen/pen/OPJmxQR)
39
-
40
- ### Basic Example
41
-
42
- ```html
43
- <!DOCTYPE html>
44
- <html lang="en">
45
- <body>
46
- <corti-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 dictation = document.getElementById('transcript');
55
- dictation.setAccessToken('YOUR_AUTH_TOKEN'); // Note: Never hardcode tokens
56
- // Listen for events
57
- dictationEl.addEventListener('transcript', e => {
58
- document.getElementById('transcript').value += e.detail.data.text + ' ';
59
- });
60
- </script>
61
- </body>
62
- </html>
63
- ```
64
-
65
- ## API Reference
66
-
67
- ### Properties
68
-
69
- | Property | Type | Description |
70
- | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
71
- | `devices` | Array | List of available recording devices. |
72
- | `selectedDevice` | Object | The selected device used for recording (MediaDeviceInfo). |
73
- | `recordingState` | String | Current state of recording (`stopped`, `recording`, `initializing` and `stopping`, ). |
74
- | `dictationConfig` | Object | Configuration settings for dictation. |
75
- | `debug_displayAudio` | Boolean | Overrides any device selection and instead uses getDisplayMedia to stream system audio. Should only be used for debugging |
76
-
77
- ### Methods
78
-
79
- | Method | Description |
80
- | -------------------------------------- | ---------------------------------------------------------------- |
81
- | `toggleRecording()` | Starts or stops recording. |
82
- | `setAccessToken(access_token: string)` | Set the latest access token. This will return the server config. |
83
-
84
- ### Events
85
-
86
- | Event | Description |
87
- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
88
- | `ready` | Fired once the component is ready. |
89
- | `recording-state-changed` | Fired when the recording state changes. `detail.state` contains the new state. |
90
- | `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. |
91
- | `transcript` | Fired when a new transcript is received. `detail.data.text` contains the transcribed text. |
92
- | `command` | Fired whenever a new command is detected. |
93
- | `audio-level-changed` | Fired when the input audio level changes. `detail.audioLevel` contains the new level. |
94
- | `error` | Fired on error. `detail` contains the full error. |
95
-
96
- ## Authentication
97
-
98
- This SDK does not handle OAuth 2.0 authentication. The client must provide an API key or access token as a string using `setAccessToken`.
99
-
100
- ## Usage Examples
101
-
102
- 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.
103
-
104
- ## Styling
105
-
106
- ![UI Overview](https://github.com/corticph/dictation-web-sdk/blob/main/docs/ui.png)
107
-
108
- 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.
109
-
110
- ## License
111
-
112
- This SDK is licensed under MIT.
113
-
114
- ## Support
115
-
116
- For issues or questions, contact **Corti Support** at [support@corti.ai](mailto:help@corti.ai).
1
+ # Corti Dictation SDK
2
+
3
+ ## Overview
4
+
5
+ The **Corti Dictation SDK** 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
+
7
+ > **Note:** OAuth 2.0 authentication is not handled by this SDK. The client must provide an API key or authorization token before using the component.
8
+
9
+ ## Installation
10
+
11
+ Include the SDK in your project by importing the JavaScript module:
12
+
13
+ ```html
14
+ npm i @corti/dictation-web
15
+ ```
16
+
17
+ Then import the module like so:
18
+
19
+ ```js
20
+ // Import the Corti Dictation SDK
21
+ import '@corti/dictation-web';
22
+ ```
23
+
24
+ Alternatively, use a CDN to start quickly (not recommended).
25
+
26
+ ```html
27
+ <script
28
+ src="https://cdn.jsdelivr.net/npm/@corti/dictation-web/dist/bundle.min.js"
29
+ preload
30
+ type="module"
31
+ ></script>
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### Demo
37
+
38
+ 🚀 [Hosted Demo](https://codepen.io/hccullen/pen/OPJmxQR)
39
+
40
+ ### Basic Example
41
+
42
+ ```html
43
+ <!DOCTYPE html>
44
+ <html lang="en">
45
+ <body>
46
+ <corti-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 dictation = document.getElementById('transcript');
55
+ dictation.setAccessToken('YOUR_AUTH_TOKEN'); // Note: Never hardcode tokens
56
+ // Listen for events
57
+ dictationEl.addEventListener('transcript', e => {
58
+ document.getElementById('transcript').value += e.detail.data.text + ' ';
59
+ });
60
+ </script>
61
+ </body>
62
+ </html>
63
+ ```
64
+
65
+ ## API Reference
66
+
67
+ ### Properties
68
+
69
+ | Property | Type | Description |
70
+ | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
71
+ | `devices` | Array | List of available recording devices. |
72
+ | `selectedDevice` | Object | The selected device used for recording (MediaDeviceInfo). |
73
+ | `recordingState` | String | Current state of recording (`stopped`, `recording`, `initializing` and `stopping`, ). |
74
+ | `dictationConfig` | Object | Configuration settings for dictation. |
75
+ | `languagesSupported` | String[] | List of all language codes available for use on the SDK. |
76
+ | `debug_displayAudio` | Boolean | Overrides any device selection and instead uses getDisplayMedia to stream system audio. Should only be used for debugging |
77
+
78
+ ### Methods
79
+
80
+ | Method | Description |
81
+ | -------------------------------------- | ---------------------------------------------------------------- |
82
+ | `toggleRecording()` | Starts or stops recording. |
83
+ | `setAccessToken(access_token: string)` | Set the latest access token. This will return the server config. |
84
+
85
+ ### Events
86
+
87
+ | Event | Description |
88
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
89
+ | `ready` | Fired once the component is ready. |
90
+ | `recording-state-changed` | Fired when the recording state changes. `detail.state` contains the new state. |
91
+ | `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. |
92
+ | `transcript` | Fired when a new transcript is received. `detail.data.text` contains the transcribed text. |
93
+ | `command` | Fired whenever a new command is detected. |
94
+ | `audio-level-changed` | Fired when the input audio level changes. `detail.audioLevel` contains the new level. |
95
+ | `error` | Fired on error. `detail` contains the full error. |
96
+
97
+ ## Authentication
98
+
99
+ This SDK does not handle OAuth 2.0 authentication. The client must provide an API key or access token as a string using `setAccessToken`.
100
+
101
+ ## Usage Examples
102
+
103
+ 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.
104
+
105
+ ## Styling
106
+
107
+ ![UI Overview](https://github.com/corticph/dictation-web-sdk/blob/main/docs/ui.png)
108
+
109
+ 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.
110
+
111
+ ## License
112
+
113
+ This SDK is licensed under MIT.
114
+
115
+ ## Support
116
+
117
+ For issues or questions, contact **Corti Support** at [support@corti.ai](mailto:help@corti.ai).
@@ -6,6 +6,7 @@ import type { DictationConfig, RecordingState } from './types.js';
6
6
  export declare class CortiDictation extends LitElement {
7
7
  static styles: import("lit").CSSResult[];
8
8
  dictationConfig: DictationConfig;
9
+ languagesSupported: string[];
9
10
  debug_displayAudio: boolean;
10
11
  private _serverConfig;
11
12
  private _audioLevel;
@@ -24,8 +25,10 @@ export declare class CortiDictation extends LitElement {
24
25
  get recordingState(): RecordingState;
25
26
  get devices(): MediaDeviceInfo[];
26
27
  setRecordingDevice(device: MediaDeviceInfo): Promise<void>;
28
+ setPrimaryLanguage(language: string): void;
27
29
  _toggleRecording(): void;
28
30
  _onRecordingDevicesChanged(event: Event): Promise<void>;
31
+ _onLanguageChanged(event: Event): void;
29
32
  render(): import("lit-html").TemplateResult<1>;
30
33
  }
31
34
  export default CortiDictation;
@@ -14,13 +14,14 @@ import './icons/icons.js';
14
14
  import ThemeStyles from './styles/theme.js';
15
15
  import ButtonStyles from './styles/buttons.js';
16
16
  import ComponentStyles from './styles/ComponentStyles.js';
17
- import { DEFAULT_DICTATION_CONFIG } from './constants.js';
17
+ import { DEFAULT_DICTATION_CONFIG, LANGUAGES_SUPPORTED } from './constants.js';
18
18
  import CalloutStyles from './styles/callout.js';
19
19
  import { decodeToken } from './utils.js';
20
20
  export class CortiDictation extends LitElement {
21
21
  constructor() {
22
22
  super(...arguments);
23
23
  this.dictationConfig = DEFAULT_DICTATION_CONFIG;
24
+ this.languagesSupported = LANGUAGES_SUPPORTED;
24
25
  this.debug_displayAudio = false;
25
26
  this._audioLevel = 0;
26
27
  this._recordingState = 'stopped';
@@ -109,6 +110,23 @@ export class CortiDictation extends LitElement {
109
110
  });
110
111
  }
111
112
  }
113
+ setPrimaryLanguage(language) {
114
+ if (LANGUAGES_SUPPORTED.includes(language)) {
115
+ this.dictationConfig = {
116
+ ...this.dictationConfig,
117
+ primaryLanguage: language,
118
+ };
119
+ // If recording is in progress, restart to apply the language change
120
+ if (this._serverConfig && this._recordingState === 'recording') {
121
+ this.recorderManager.stopRecording();
122
+ this.recorderManager.startRecording({
123
+ dictationConfig: this.dictationConfig,
124
+ serverConfig: this._serverConfig,
125
+ debug_displayAudio: this.debug_displayAudio,
126
+ });
127
+ }
128
+ }
129
+ }
112
130
  _toggleRecording() {
113
131
  if (!this._serverConfig)
114
132
  return;
@@ -128,6 +146,14 @@ export class CortiDictation extends LitElement {
128
146
  const customEvent = event;
129
147
  this.setRecordingDevice(customEvent.detail.selectedDevice);
130
148
  }
149
+ // Handle language change events
150
+ _onLanguageChanged(event) {
151
+ const customEvent = event;
152
+ const language = customEvent.detail.language;
153
+ if (language) {
154
+ this.setPrimaryLanguage(language);
155
+ }
156
+ }
131
157
  render() {
132
158
  if (!this._serverConfig) {
133
159
  return html ` <div style="display: none"></div> `;
@@ -154,8 +180,10 @@ export class CortiDictation extends LitElement {
154
180
 
155
181
  <settings-menu
156
182
  .selectedDevice=${this._selectedDevice}
183
+ .selectedLanguage=${this.dictationConfig.primaryLanguage}
157
184
  ?settingsDisabled=${this._recordingState !== 'stopped'}
158
185
  @recording-devices-changed=${this._onRecordingDevicesChanged}
186
+ @language-changed=${this._onLanguageChanged}
159
187
  ></settings-menu>
160
188
  </div>
161
189
  `;
@@ -165,6 +193,9 @@ CortiDictation.styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyl
165
193
  __decorate([
166
194
  property({ type: Object })
167
195
  ], CortiDictation.prototype, "dictationConfig", void 0);
196
+ __decorate([
197
+ property({ type: Array })
198
+ ], CortiDictation.prototype, "languagesSupported", void 0);
168
199
  __decorate([
169
200
  property({ type: Boolean })
170
201
  ], CortiDictation.prototype, "debug_displayAudio", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../src/CortiDictation.ts"],"names":[],"mappings":";;;;;;AAAA,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,MAAM,gBAAgB,CAAC;AAC1D,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,OAAO,cAAe,SAAQ,UAAU;IAA9C;;QAIE,oBAAe,GAAoB,wBAAwB,CAAC;QAG5D,uBAAkB,GAAY,KAAK,CAAC;QAM5B,gBAAW,GAAW,CAAC,CAAC;QAGxB,oBAAe,GAAmB,SAAS,CAAC;QAM5C,aAAQ,GAAsB,EAAE,CAAC;QAEjC,oBAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAmJlD,CAAC;IAjJC,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;SACR,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,IAAI;oBACb,QAAQ,EAAE,IAAI;iBACf,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,eAAe;QACpB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEM,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,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;IAED,gBAAgB;QACd,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QAChC,IAAI,IAAI,CAAC,eAAe,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC;QACvC,CAAC;aAAM,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;gBAClC,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;aAC5C,CAAC,CAAC;QACL,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,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,gBAAgB;kBACtB,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;;YAEpC,SAAS;YACT,CAAC,CAAC,IAAI,CAAA,+CAA+C;YACrD,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,IAAI,CAAA,mCAAmC;gBACzC,CAAC,CAAC,IAAI,CAAA,6BAA6B;;qBAE5B,IAAI,CAAC,WAAW;sBACf,WAAW;;;;;4BAKL,IAAI,CAAC,eAAe;8BAClB,IAAI,CAAC,eAAe,KAAK,SAAS;uCACzB,IAAI,CAAC,0BAA0B;;;KAGjE,CAAC;IACJ,CAAC;;AAzKM,qBAAM,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,CAAC,AAA9D,CAA+D;AAG5E;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDACiC;AAG5D;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;0DACQ;AAG5B;IADP,KAAK,EAAE;qDACwC;AAGxC;IADP,KAAK,EAAE;mDACwB;AAGxB;IADP,KAAK,EAAE;uDAC4C;AAG5C;IADP,KAAK,EAAE;uDAC6C;AAG7C;IADP,KAAK,EAAE;gDACiC;AAuJ3C,eAAe,cAAc,CAAC","sourcesContent":["// 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 { DictationConfig, RecordingState, ServerConfig } from './types.js';\nimport { DEFAULT_DICTATION_CONFIG } 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: DictationConfig = DEFAULT_DICTATION_CONFIG;\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 ];\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: true,\n composed: true,\n }),\n );\n });\n });\n }\n\n public toggleRecording() {\n this._toggleRecording();\n }\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 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 _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 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 ?settingsDisabled=${this._recordingState !== 'stopped'}\n @recording-devices-changed=${this._onRecordingDevicesChanged}\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":"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","sourcesContent":["// 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 { DictationConfig, 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: DictationConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Array })\n languagesSupported: string[] = 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 ];\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: true,\n composed: true,\n }),\n );\n });\n });\n }\n\n\n\n public toggleRecording() {\n this._toggleRecording();\n }\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 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"]}
package/dist/bundle.js CHANGED
@@ -1002,7 +1002,7 @@ var SelectStyles = i`
1002
1002
  var select_default = SelectStyles;
1003
1003
 
1004
1004
  // dist/constants.js
1005
- var LANGUAGES_SUPPORTED = ["en", "da"];
1005
+ var LANGUAGES_SUPPORTED = ["en", "en-GB", "da", "de", "fr", "de-CH", "sv", "es", "it", "nl", "no", "pt"];
1006
1006
  var DEFAULT_DICTATION_CONFIG = {
1007
1007
  primaryLanguage: "en",
1008
1008
  interimResults: true,
@@ -1051,6 +1051,9 @@ var __decorate = function(decorators, target, key, desc) {
1051
1051
  return c4 > 3 && r7 && Object.defineProperty(target, key, r7), r7;
1052
1052
  };
1053
1053
  var SettingsMenu = class SettingsMenu2 extends r4 {
1054
+ get effectiveSelectedLanguage() {
1055
+ return this.selectedLanguage || LANGUAGES_SUPPORTED[0] || "";
1056
+ }
1054
1057
  constructor() {
1055
1058
  super();
1056
1059
  this.selectedLanguage = "";
@@ -1083,6 +1086,19 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
1083
1086
  composed: true
1084
1087
  }));
1085
1088
  }
1089
+ _selectLanguage(language) {
1090
+ if (!LANGUAGES_SUPPORTED.includes(language)) {
1091
+ return;
1092
+ }
1093
+ this.selectedLanguage = language;
1094
+ this.dispatchEvent(new CustomEvent("language-changed", {
1095
+ detail: {
1096
+ language
1097
+ },
1098
+ bubbles: true,
1099
+ composed: true
1100
+ }));
1101
+ }
1086
1102
  render() {
1087
1103
  return x`
1088
1104
  <div class="mic-selector">
@@ -1111,7 +1127,7 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
1111
1127
  ${this._devices.map((device) => x`
1112
1128
  <option
1113
1129
  value=${device.deviceId}
1114
- ?selected=${this.selectedDevice === device}
1130
+ ?selected=${this.selectedDevice?.deviceId === device.deviceId}
1115
1131
  >
1116
1132
  ${device.label || "Unknown Device"}
1117
1133
  </option>
@@ -1126,14 +1142,14 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
1126
1142
  id="language-select"
1127
1143
  aria-labelledby="language-select-label"
1128
1144
  @change=${(e5) => {
1129
- this._selectDevice(e5.target.value);
1145
+ this._selectLanguage(e5.target.value);
1130
1146
  }}
1131
1147
  ?disabled=${this.settingsDisabled}
1132
1148
  >
1133
1149
  ${LANGUAGES_SUPPORTED.map((language) => x`
1134
1150
  <option
1135
1151
  value=${language}
1136
- ?selected=${this.selectedLanguage === language}
1152
+ ?selected=${this.effectiveSelectedLanguage === language}
1137
1153
  >
1138
1154
  ${getLanguageName(language)}
1139
1155
  </option>
@@ -1185,7 +1201,7 @@ SettingsMenu.styles = [
1185
1201
  callout_default
1186
1202
  ];
1187
1203
  __decorate([
1188
- n4({ type: String })
1204
+ n4({ type: Object })
1189
1205
  ], SettingsMenu.prototype, "selectedDevice", void 0);
1190
1206
  __decorate([
1191
1207
  n4({ type: String })
@@ -1530,6 +1546,7 @@ var CortiDictation = class extends r4 {
1530
1546
  constructor() {
1531
1547
  super(...arguments);
1532
1548
  this.dictationConfig = DEFAULT_DICTATION_CONFIG;
1549
+ this.languagesSupported = LANGUAGES_SUPPORTED;
1533
1550
  this.debug_displayAudio = false;
1534
1551
  this._audioLevel = 0;
1535
1552
  this._recordingState = "stopped";
@@ -1614,6 +1631,22 @@ var CortiDictation = class extends r4 {
1614
1631
  });
1615
1632
  }
1616
1633
  }
1634
+ setPrimaryLanguage(language) {
1635
+ if (LANGUAGES_SUPPORTED.includes(language)) {
1636
+ this.dictationConfig = {
1637
+ ...this.dictationConfig,
1638
+ primaryLanguage: language
1639
+ };
1640
+ if (this._serverConfig && this._recordingState === "recording") {
1641
+ this.recorderManager.stopRecording();
1642
+ this.recorderManager.startRecording({
1643
+ dictationConfig: this.dictationConfig,
1644
+ serverConfig: this._serverConfig,
1645
+ debug_displayAudio: this.debug_displayAudio
1646
+ });
1647
+ }
1648
+ }
1649
+ }
1617
1650
  _toggleRecording() {
1618
1651
  if (!this._serverConfig)
1619
1652
  return;
@@ -1632,6 +1665,14 @@ var CortiDictation = class extends r4 {
1632
1665
  const customEvent = event;
1633
1666
  this.setRecordingDevice(customEvent.detail.selectedDevice);
1634
1667
  }
1668
+ // Handle language change events
1669
+ _onLanguageChanged(event) {
1670
+ const customEvent = event;
1671
+ const language = customEvent.detail.language;
1672
+ if (language) {
1673
+ this.setPrimaryLanguage(language);
1674
+ }
1675
+ }
1635
1676
  render() {
1636
1677
  if (!this._serverConfig) {
1637
1678
  return x` <div style="display: none"></div> `;
@@ -1653,8 +1694,10 @@ var CortiDictation = class extends r4 {
1653
1694
 
1654
1695
  <settings-menu
1655
1696
  .selectedDevice=${this._selectedDevice}
1697
+ .selectedLanguage=${this.dictationConfig.primaryLanguage}
1656
1698
  ?settingsDisabled=${this._recordingState !== "stopped"}
1657
1699
  @recording-devices-changed=${this._onRecordingDevicesChanged}
1700
+ @language-changed=${this._onLanguageChanged}
1658
1701
  ></settings-menu>
1659
1702
  </div>
1660
1703
  `;
@@ -1664,6 +1707,9 @@ CortiDictation.styles = [buttons_default, theme_default, ComponentStyles_default
1664
1707
  __decorate4([
1665
1708
  n4({ type: Object })
1666
1709
  ], CortiDictation.prototype, "dictationConfig", void 0);
1710
+ __decorate4([
1711
+ n4({ type: Array })
1712
+ ], CortiDictation.prototype, "languagesSupported", void 0);
1667
1713
  __decorate4([
1668
1714
  n4({ type: Boolean })
1669
1715
  ], CortiDictation.prototype, "debug_displayAudio", void 0);
@@ -4,11 +4,13 @@ export declare class SettingsMenu extends LitElement {
4
4
  selectedLanguage: string;
5
5
  settingsDisabled: boolean;
6
6
  private _devices;
7
+ get effectiveSelectedLanguage(): string;
7
8
  constructor();
8
9
  connectedCallback(): Promise<void>;
9
10
  private handleDevicesChange;
10
11
  static styles: CSSResultGroup;
11
12
  private _selectDevice;
13
+ private _selectLanguage;
12
14
  render(): TemplateResult;
13
15
  }
14
16
  declare global {
@@ -13,6 +13,9 @@ import { LANGUAGES_SUPPORTED } from '../constants.js';
13
13
  import { getAudioDevices, getLanguageName } from '../utils.js';
14
14
  import CalloutStyles from '../styles/callout.js';
15
15
  let SettingsMenu = class SettingsMenu extends LitElement {
16
+ get effectiveSelectedLanguage() {
17
+ return this.selectedLanguage || LANGUAGES_SUPPORTED[0] || '';
18
+ }
16
19
  constructor() {
17
20
  super();
18
21
  this.selectedLanguage = '';
@@ -46,111 +49,124 @@ let SettingsMenu = class SettingsMenu extends LitElement {
46
49
  composed: true,
47
50
  }));
48
51
  }
52
+ _selectLanguage(language) {
53
+ if (!LANGUAGES_SUPPORTED.includes(language)) {
54
+ return;
55
+ }
56
+ this.selectedLanguage = language;
57
+ this.dispatchEvent(new CustomEvent('language-changed', {
58
+ detail: {
59
+ language: language,
60
+ },
61
+ bubbles: true,
62
+ composed: true,
63
+ }));
64
+ }
49
65
  render() {
50
- return html `
51
- <div class="mic-selector">
52
- <button id="settings-popover-button" popovertarget="settings-popover">
53
- <icon-settings></icon-settings>
54
- </button>
55
- <div id="settings-popover" popover>
56
- <div class="settings-wrapper">
66
+ return html `
67
+ <div class="mic-selector">
68
+ <button id="settings-popover-button" popovertarget="settings-popover">
69
+ <icon-settings></icon-settings>
70
+ </button>
71
+ <div id="settings-popover" popover>
72
+ <div class="settings-wrapper">
57
73
  ${this.settingsDisabled
58
- ? html `
59
- <div class="callout warn">
60
- Recording is in progress. Stop recording to change settings.
61
- </div>
74
+ ? html `
75
+ <div class="callout warn">
76
+ Recording is in progress. Stop recording to change settings.
77
+ </div>
62
78
  `
63
- : ''}
64
- <div class="form-group">
65
- <label id="device-select-label" for="device-select">
66
- Recording Device
67
- </label>
68
- <select
69
- id="device-select"
70
- aria-labelledby="device-select-label"
79
+ : ''}
80
+ <div class="form-group">
81
+ <label id="device-select-label" for="device-select">
82
+ Recording Device
83
+ </label>
84
+ <select
85
+ id="device-select"
86
+ aria-labelledby="device-select-label"
71
87
  @change=${(e) => {
72
88
  this._selectDevice(e.target.value);
73
- }}
74
- ?disabled=${this.settingsDisabled}
75
- >
76
- ${this._devices.map(device => html `
77
- <option
78
- value=${device.deviceId}
79
- ?selected=${this.selectedDevice === device}
80
- >
81
- ${device.label || 'Unknown Device'}
82
- </option>
83
- `)}
84
- </select>
85
- </div>
86
- <div class="form-group">
87
- <label id="language-select-label" for="language-select">
88
- Dictation Language
89
- </label>
90
- <select
91
- id="language-select"
92
- aria-labelledby="language-select-label"
89
+ }}
90
+ ?disabled=${this.settingsDisabled}
91
+ >
92
+ ${this._devices.map(device => html `
93
+ <option
94
+ value=${device.deviceId}
95
+ ?selected=${this.selectedDevice?.deviceId === device.deviceId}
96
+ >
97
+ ${device.label || 'Unknown Device'}
98
+ </option>
99
+ `)}
100
+ </select>
101
+ </div>
102
+ <div class="form-group">
103
+ <label id="language-select-label" for="language-select">
104
+ Dictation Language
105
+ </label>
106
+ <select
107
+ id="language-select"
108
+ aria-labelledby="language-select-label"
93
109
  @change=${(e) => {
94
- this._selectDevice(e.target.value);
95
- }}
96
- ?disabled=${this.settingsDisabled}
97
- >
98
- ${LANGUAGES_SUPPORTED.map(language => html `
99
- <option
100
- value=${language}
101
- ?selected=${this.selectedLanguage === language}
102
- >
103
- ${getLanguageName(language)}
104
- </option>
105
- `)}
106
- </select>
107
- </div>
108
- </div>
109
- </div>
110
- </div>
110
+ this._selectLanguage(e.target.value);
111
+ }}
112
+ ?disabled=${this.settingsDisabled}
113
+ >
114
+ ${LANGUAGES_SUPPORTED.map(language => html `
115
+ <option
116
+ value=${language}
117
+ ?selected=${this.effectiveSelectedLanguage === language}
118
+ >
119
+ ${getLanguageName(language)}
120
+ </option>
121
+ `)}
122
+ </select>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </div>
111
127
  `;
112
128
  }
113
129
  };
114
130
  SettingsMenu.styles = [
115
- css `
116
- :host {
117
- display: block;
118
- font-family: var(--component-font-family);
119
- }
120
- /* Retain the anchor-name styling for this component */
121
- #settings-popover-button {
122
- anchor-name: --settings_popover_btn;
123
- }
124
- [popover] {
125
- margin: 0;
126
- padding: 16px;
127
- border: 0;
128
- background: var(--card-background);
129
- border: 1px solid var(--card-border-color);
130
- border-radius: var(--card-border-radius);
131
- box-shadow: var(--card-box-shadow);
132
- z-index: 1000;
133
- max-width: 260px;
134
- width: 100%;
135
- min-width: 200px;
136
- position-anchor: --settings_popover_btn;
137
- position-area: bottom span-right;
138
- position-visibility: always;
139
- position-try-fallbacks: flip-inline;
140
- overflow-x: hidden;
141
- }
142
- .settings-wrapper {
143
- display: flex;
144
- flex-direction: column;
145
- gap: 20px;
146
- }
131
+ css `
132
+ :host {
133
+ display: block;
134
+ font-family: var(--component-font-family);
135
+ }
136
+ /* Retain the anchor-name styling for this component */
137
+ #settings-popover-button {
138
+ anchor-name: --settings_popover_btn;
139
+ }
140
+ [popover] {
141
+ margin: 0;
142
+ padding: 16px;
143
+ border: 0;
144
+ background: var(--card-background);
145
+ border: 1px solid var(--card-border-color);
146
+ border-radius: var(--card-border-radius);
147
+ box-shadow: var(--card-box-shadow);
148
+ z-index: 1000;
149
+ max-width: 260px;
150
+ width: 100%;
151
+ min-width: 200px;
152
+ position-anchor: --settings_popover_btn;
153
+ position-area: bottom span-right;
154
+ position-visibility: always;
155
+ position-try-fallbacks: flip-inline;
156
+ overflow-x: hidden;
157
+ }
158
+ .settings-wrapper {
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: 20px;
162
+ }
147
163
  `,
148
164
  ButtonStyles,
149
165
  SelectStyles,
150
166
  CalloutStyles,
151
167
  ];
152
168
  __decorate([
153
- property({ type: String })
169
+ property({ type: Object })
154
170
  ], SettingsMenu.prototype, "selectedDevice", void 0);
155
171
  __decorate([
156
172
  property({ type: String })
@@ -1 +1 @@
1
- {"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":";;;;;;AAAA,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAkC,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAG1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAa1C;QACE,KAAK,EAAE,CAAC;QATV,qBAAgB,GAAW,EAAE,CAAC;QAG9B,qBAAgB,GAAY,KAAK,CAAC;QAG1B,aAAQ,GAAsB,EAAE,CAAC;QAIvC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAyCO,aAAa,CAAC,QAAgB;QACpC,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;QAC7B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,2BAA2B,EAAE;YAC3C,MAAM,EAAE;gBACN,OAAO,EAAE,IAAI,CAAC,QAAQ;gBACtB,cAAc,EAAE,MAAM;aACvB;YACD,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;cAOD,IAAI,CAAC,gBAAgB;YACrB,CAAC,CAAC,IAAI,CAAA;;;;iBAIH;YACH,CAAC,CAAC,EAAE;;;;;;;;0BAQQ,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CACjB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEF,MAAM,CAAC,QAAQ;kCACX,IAAI,CAAC,cAAc,KAAK,MAAM;;wBAExC,MAAM,CAAC,KAAK,IAAI,gBAAgB;;mBAErC,CACF;;;;;;;;;;0BAUS,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,mBAAmB,CAAC,GAAG,CACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEJ,QAAQ;kCACJ,IAAI,CAAC,gBAAgB,KAAK,QAAQ;;wBAE5C,eAAe,CAAC,QAAQ,CAAC;;mBAE9B,CACF;;;;;;KAMZ,CAAC;IACJ,CAAC;;AA7HM,mBAAM,GAAmB;IAC9B,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgCF;IACD,YAAY;IACZ,YAAY;IACZ,aAAa;CACd,AArCY,CAqCX;AApEF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oDACiB;AAG5C;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDACG;AAG9B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;sDACM;AAG1B;IADP,KAAK,EAAE;8CACiC;AAX9B,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CA+JxB","sourcesContent":["// mic-selector.ts\r\nimport { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\n\r\nimport ButtonStyles from '../styles/buttons.js';\r\nimport SelectStyles from '../styles/select.js';\r\nimport { LANGUAGES_SUPPORTED } from '../constants.js';\r\nimport { getAudioDevices, getLanguageName } from '../utils.js';\r\nimport CalloutStyles from '../styles/callout.js';\r\n\r\n@customElement('settings-menu')\r\nexport class SettingsMenu extends LitElement {\r\n @property({ type: String })\r\n selectedDevice: MediaDeviceInfo | undefined;\r\n\r\n @property({ type: String })\r\n selectedLanguage: string = '';\r\n\r\n @property({ type: Boolean })\r\n settingsDisabled: boolean = false;\r\n\r\n @state()\r\n private _devices: MediaDeviceInfo[] = [];\r\n\r\n constructor() {\r\n super();\r\n navigator.mediaDevices.addEventListener(\r\n 'devicechange',\r\n this.handleDevicesChange.bind(this),\r\n );\r\n }\r\n\r\n // on load, get the available devices\r\n async connectedCallback(): Promise<void> {\r\n super.connectedCallback();\r\n const deviceResponse = await getAudioDevices();\r\n this._devices = deviceResponse.devices;\r\n }\r\n\r\n private async handleDevicesChange() {\r\n const deviceResponse = await getAudioDevices();\r\n this._devices = deviceResponse.devices;\r\n }\r\n\r\n static styles: CSSResultGroup = [\r\n css`\r\n :host {\r\n display: block;\r\n font-family: var(--component-font-family);\r\n }\r\n /* Retain the anchor-name styling for this component */\r\n #settings-popover-button {\r\n anchor-name: --settings_popover_btn;\r\n }\r\n [popover] {\r\n margin: 0;\r\n padding: 16px;\r\n border: 0;\r\n background: var(--card-background);\r\n border: 1px solid var(--card-border-color);\r\n border-radius: var(--card-border-radius);\r\n box-shadow: var(--card-box-shadow);\r\n z-index: 1000;\r\n max-width: 260px;\r\n width: 100%;\r\n min-width: 200px;\r\n position-anchor: --settings_popover_btn;\r\n position-area: bottom span-right;\r\n position-visibility: always;\r\n position-try-fallbacks: flip-inline;\r\n overflow-x: hidden;\r\n }\r\n .settings-wrapper {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 20px;\r\n }\r\n `,\r\n ButtonStyles,\r\n SelectStyles,\r\n CalloutStyles,\r\n ];\r\n\r\n private _selectDevice(deviceId: string): void {\r\n // Find the device object\r\n const device = this._devices.find(d => d.deviceId === deviceId);\r\n if (!device) {\r\n return;\r\n }\r\n this.selectedDevice = device;\r\n this.dispatchEvent(\r\n new CustomEvent('recording-devices-changed', {\r\n detail: {\r\n devices: this._devices,\r\n selectedDevice: device,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n render(): TemplateResult {\r\n return html`\r\n <div class=\"mic-selector\">\r\n <button id=\"settings-popover-button\" popovertarget=\"settings-popover\">\r\n <icon-settings></icon-settings>\r\n </button>\r\n <div id=\"settings-popover\" popover>\r\n <div class=\"settings-wrapper\">\r\n ${this.settingsDisabled\r\n ? html`\r\n <div class=\"callout warn\">\r\n Recording is in progress. Stop recording to change settings.\r\n </div>\r\n `\r\n : ''}\r\n <div class=\"form-group\">\r\n <label id=\"device-select-label\" for=\"device-select\">\r\n Recording Device\r\n </label>\r\n <select\r\n id=\"device-select\"\r\n aria-labelledby=\"device-select-label\"\r\n @change=${(e: Event) => {\r\n this._selectDevice((e.target as HTMLSelectElement).value);\r\n }}\r\n ?disabled=${this.settingsDisabled}\r\n >\r\n ${this._devices.map(\r\n device => html`\r\n <option\r\n value=${device.deviceId}\r\n ?selected=${this.selectedDevice === device}\r\n >\r\n ${device.label || 'Unknown Device'}\r\n </option>\r\n `,\r\n )}\r\n </select>\r\n </div>\r\n <div class=\"form-group\">\r\n <label id=\"language-select-label\" for=\"language-select\">\r\n Dictation Language\r\n </label>\r\n <select\r\n id=\"language-select\"\r\n aria-labelledby=\"language-select-label\"\r\n @change=${(e: Event) => {\r\n this._selectDevice((e.target as HTMLSelectElement).value);\r\n }}\r\n ?disabled=${this.settingsDisabled}\r\n >\r\n ${LANGUAGES_SUPPORTED.map(\r\n language => html`\r\n <option\r\n value=${language}\r\n ?selected=${this.selectedLanguage === language}\r\n >\r\n ${getLanguageName(language)}\r\n </option>\r\n `,\r\n )}\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'settings-menu': SettingsMenu;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":";;;;;;AAAA,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAkC,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAG1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAa1C,IAAI,yBAAyB;QAC3B,OAAO,IAAI,CAAC,gBAAgB,IAAI,mBAAmB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,CAAC;IAED;QACE,KAAK,EAAE,CAAC;QAbV,qBAAgB,GAAW,EAAE,CAAC;QAG9B,qBAAgB,GAAY,KAAK,CAAC;QAG1B,aAAQ,GAAsB,EAAE,CAAC;QAQvC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAwCO,aAAa,CAAC,QAAgB;QACpC,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;QAC7B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,2BAA2B,EAAE;YAC3C,MAAM,EAAE;gBACN,OAAO,EAAE,IAAI,CAAC,QAAQ;gBACtB,cAAc,EAAE,MAAM;aACvB;YACD,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,eAAe,CAAC,QAAgB;QACtC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,kBAAkB,EAAE;YAClC,MAAM,EAAE;gBACN,QAAQ,EAAE,QAAQ;aACnB;YACD,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;cAOD,IAAI,CAAC,gBAAgB;YACrB,CAAC,CAAC,IAAI,CAAA;;;;iBAIH;YACH,CAAC,CAAC,EAAE;;;;;;;;0BAQQ,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CACjB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEF,MAAM,CAAC,QAAQ;kCACX,IAAI,CAAC,cAAc,EAAE,QAAQ,KAAK,MAAM,CAAC,QAAQ;;wBAE3D,MAAM,CAAC,KAAK,IAAI,gBAAgB;;mBAErC,CACF;;;;;;;;;;0BAUS,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,eAAe,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC9D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,mBAAmB,CAAC,GAAG,CACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEJ,QAAQ;kCACJ,IAAI,CAAC,yBAAyB,KAAK,QAAQ;;wBAErD,eAAe,CAAC,QAAQ,CAAC;;mBAE9B,CACF;;;;;;KAMZ,CAAC;IACJ,CAAC;;AA5IM,mBAAM,GAAmB;IAC9B,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgCF;IACD,YAAY;IACZ,YAAY;IACZ,aAAa;CACd,AArCY,CAqCX;AAxEF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oDACiB;AAG5C;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDACG;AAG9B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;sDACM;AAG1B;IADP,KAAK,EAAE;8CACiC;AAX9B,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAkLxB","sourcesContent":["// mic-selector.ts\nimport { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport ButtonStyles from '../styles/buttons.js';\nimport SelectStyles from '../styles/select.js';\nimport { LANGUAGES_SUPPORTED } from '../constants.js';\nimport { getAudioDevices, getLanguageName } from '../utils.js';\nimport CalloutStyles from '../styles/callout.js';\n\n@customElement('settings-menu')\nexport class SettingsMenu extends LitElement {\n @property({ type: Object })\n selectedDevice: MediaDeviceInfo | undefined;\n\n @property({ type: String })\n selectedLanguage: string = '';\n\n @property({ type: Boolean })\n settingsDisabled: boolean = false;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n get effectiveSelectedLanguage(): string {\n return this.selectedLanguage || LANGUAGES_SUPPORTED[0] || '';\n }\n\n constructor() {\n super();\n navigator.mediaDevices.addEventListener(\n 'devicechange',\n this.handleDevicesChange.bind(this),\n );\n }\n\n // on load, get the available devices\n async connectedCallback(): Promise<void> {\n super.connectedCallback();\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n private async handleDevicesChange() {\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: block;\n font-family: var(--component-font-family);\n }\n /* Retain the anchor-name styling for this component */\n #settings-popover-button {\n anchor-name: --settings_popover_btn;\n }\n [popover] {\n margin: 0;\n padding: 16px;\n border: 0;\n background: var(--card-background);\n border: 1px solid var(--card-border-color);\n border-radius: var(--card-border-radius);\n box-shadow: var(--card-box-shadow);\n z-index: 1000;\n max-width: 260px;\n width: 100%;\n min-width: 200px;\n position-anchor: --settings_popover_btn;\n position-area: bottom span-right;\n position-visibility: always;\n position-try-fallbacks: flip-inline;\n overflow-x: hidden;\n }\n .settings-wrapper {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n `,\n ButtonStyles,\n SelectStyles,\n CalloutStyles,\n ];\n private _selectDevice(deviceId: string): void {\n // Find the device object\n const device = this._devices.find(d => d.deviceId === deviceId);\n if (!device) {\n return;\n }\n this.selectedDevice = device;\n this.dispatchEvent(\n new CustomEvent('recording-devices-changed', {\n detail: {\n devices: this._devices,\n selectedDevice: device,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private _selectLanguage(language: string): void {\n if (!LANGUAGES_SUPPORTED.includes(language)) {\n return;\n }\n this.selectedLanguage = language;\n this.dispatchEvent(\n new CustomEvent('language-changed', {\n detail: {\n language: language,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"mic-selector\">\n <button id=\"settings-popover-button\" popovertarget=\"settings-popover\">\n <icon-settings></icon-settings>\n </button>\n <div id=\"settings-popover\" popover>\n <div class=\"settings-wrapper\">\n ${this.settingsDisabled\n ? html`\n <div class=\"callout warn\">\n Recording is in progress. Stop recording to change settings.\n </div>\n `\n : ''}\n <div class=\"form-group\">\n <label id=\"device-select-label\" for=\"device-select\">\n Recording Device\n </label>\n <select\n id=\"device-select\"\n aria-labelledby=\"device-select-label\"\n @change=${(e: Event) => {\n this._selectDevice((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${this._devices.map(\n device => html`\n <option\n value=${device.deviceId}\n ?selected=${this.selectedDevice?.deviceId === device.deviceId}\n >\n ${device.label || 'Unknown Device'}\n </option>\n `,\n )}\n </select>\n </div>\n <div class=\"form-group\">\n <label id=\"language-select-label\" for=\"language-select\">\n Dictation Language\n </label>\n <select\n id=\"language-select\"\n aria-labelledby=\"language-select-label\"\n @change=${(e: Event) => {\n this._selectLanguage((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${LANGUAGES_SUPPORTED.map(\n language => html`\n <option\n value=${language}\n ?selected=${this.effectiveSelectedLanguage === language}\n >\n ${getLanguageName(language)}\n </option>\n `,\n )}\n </select>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'settings-menu': SettingsMenu;\n }\n}\n"]}
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const LANGUAGES_SUPPORTED = ['en', 'da'];
1
+ export const LANGUAGES_SUPPORTED = ['en', 'en-GB', 'da', 'de', 'fr', 'de-CH', 'sv', 'es', 'it', 'nl', 'no', 'pt'];
2
2
  export const DEFAULT_DICTATION_CONFIG = {
3
3
  primaryLanguage: 'en',
4
4
  interimResults: true,
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;CAC3B,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\r\n\r\nexport const LANGUAGES_SUPPORTED = ['en', 'da'];\r\nexport const DEFAULT_DICTATION_CONFIG: DictationConfig = {\r\n primaryLanguage: 'en',\r\n interimResults: true,\r\n spokenPunctuation: true,\r\n automaticPunctuation: true,\r\n};\r\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAClH,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;CAC3B,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\n\nexport const LANGUAGES_SUPPORTED = ['en', 'en-GB', 'da', 'de', 'fr', 'de-CH', 'sv', 'es', 'it', 'nl', 'no', 'pt'];\nexport const DEFAULT_DICTATION_CONFIG: DictationConfig = {\n primaryLanguage: 'en',\n interimResults: true,\n spokenPunctuation: true,\n automaticPunctuation: true,\n};"]}
package/package.json CHANGED
@@ -1,117 +1,117 @@
1
- {
2
- "name": "@corti/dictation-web",
3
- "description": "Web component for Corti Dictation",
4
- "author": "Corti ApS",
5
- "version": "0.1.12",
6
- "license": "MIT",
7
- "type": "module",
8
- "main": "dist/index.js",
9
- "module": "dist/index.js",
10
- "exports": {
11
- "import": "./dist/index.js",
12
- "default": "./dist/bundle.js"
13
- },
14
- "jsdelivr": "./dist/bundle.js",
15
- "files": [
16
- "dist"
17
- ],
18
- "bugs": {
19
- "url": "https://help.corti.app",
20
- "email": "help@corti.ai"
21
- },
22
- "repository": "github:corticph/dictation-web-sdk",
23
- "homepage": "https://help.corti.app/en/articles/10714657-introducing-the-corti-dictation-browser-sdk",
24
- "keywords": [
25
- "corti",
26
- "dictation",
27
- "web",
28
- "sdk",
29
- "speech",
30
- "recognition",
31
- "transcription",
32
- "audio",
33
- "medical",
34
- "healthcare"
35
- ],
36
- "scripts": {
37
- "analyze": "cem analyze --litelement",
38
- "build": "tsc && npm run analyze -- --exclude dist",
39
- "build:bundle": "esbuild dist/index.js --bundle --outfile=dist/bundle.js --format=esm --platform=browser",
40
- "release": "npm run build && npm run build:bundle && npm publish --access public",
41
- "start": "npm run build && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
42
- "prepublish": "tsc && npm run analyze -- --exclude dist",
43
- "lint": "eslint --ext .ts,.tsx src --ignore-path .gitignore && prettier \"src/**/*.ts\" --check --ignore-path .gitignore",
44
- "format": "eslint --ext .ts,.tsx src --fix --ignore-path .gitignore && prettier \"src/**/*.ts\" --write --ignore-path .gitignore",
45
- "prepare": "husky && husky install",
46
- "test": "tsc && wtr --coverage",
47
- "test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\"",
48
- "storybook": "tsc && npm run analyze -- --exclude dist && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"storybook dev -p 8080\"",
49
- "storybook:build": "tsc && npm run analyze -- --exclude dist && storybook build"
50
- },
51
- "dependencies": {
52
- "lit": "^3.1.4"
53
- },
54
- "devDependencies": {
55
- "@custom-elements-manifest/analyzer": "^0.10.3",
56
- "@open-wc/eslint-config": "^12.0.3",
57
- "@open-wc/testing": "^4.0.0",
58
- "@storybook/addon-a11y": "^7.6.20",
59
- "@storybook/addon-essentials": "^7.6.20",
60
- "@storybook/addon-links": "^7.6.20",
61
- "@storybook/web-components": "^7.6.20",
62
- "@types/mocha": "^10.0.7",
63
- "@typescript-eslint/eslint-plugin": "^7.18.0",
64
- "@typescript-eslint/parser": "^7.18.0",
65
- "@web/dev-server": "^0.4.6",
66
- "@web/storybook-builder": "^0.1.16",
67
- "@web/storybook-framework-web-components": "^0.1.2",
68
- "@web/test-runner": "^0.18.2",
69
- "concurrently": "^8.2.2",
70
- "esbuild": "^0.25.0",
71
- "eslint": "^8.57.0",
72
- "eslint-config-prettier": "^9.1.0",
73
- "eslint-plugin-html": "^8.1.2",
74
- "husky": "^8.0.0",
75
- "lint-staged": "^15.2.7",
76
- "prettier": "^3.3.2",
77
- "sinon": "^19.0.2",
78
- "storybook": "^7.6.20",
79
- "tslib": "^2.6.3",
80
- "typescript": "^5.5.3"
81
- },
82
- "customElements": "custom-elements.json",
83
- "eslintConfig": {
84
- "parser": "@typescript-eslint/parser",
85
- "extends": [
86
- "@open-wc",
87
- "prettier"
88
- ],
89
- "plugins": [
90
- "@typescript-eslint"
91
- ],
92
- "rules": {
93
- "no-unused-vars": "off",
94
- "@typescript-eslint/no-unused-vars": [
95
- "error"
96
- ],
97
- "import/no-unresolved": "off",
98
- "import/extensions": [
99
- "error",
100
- "always",
101
- {
102
- "ignorePackages": true
103
- }
104
- ]
105
- }
106
- },
107
- "prettier": {
108
- "singleQuote": true,
109
- "arrowParens": "avoid"
110
- },
111
- "lint-staged": {
112
- "*.ts": [
113
- "eslint --fix",
114
- "prettier --write"
115
- ]
116
- }
117
- }
1
+ {
2
+ "name": "@corti/dictation-web",
3
+ "description": "Web component for Corti Dictation",
4
+ "author": "Corti ApS",
5
+ "version": "0.1.14",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "module": "dist/index.js",
10
+ "exports": {
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/bundle.js"
13
+ },
14
+ "jsdelivr": "./dist/bundle.js",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "bugs": {
19
+ "url": "https://help.corti.app",
20
+ "email": "help@corti.ai"
21
+ },
22
+ "repository": "github:corticph/dictation-web-sdk",
23
+ "homepage": "https://help.corti.app/en/articles/10714657-introducing-the-corti-dictation-browser-sdk",
24
+ "keywords": [
25
+ "corti",
26
+ "dictation",
27
+ "web",
28
+ "sdk",
29
+ "speech",
30
+ "recognition",
31
+ "transcription",
32
+ "audio",
33
+ "medical",
34
+ "healthcare"
35
+ ],
36
+ "scripts": {
37
+ "analyze": "cem analyze --litelement",
38
+ "build": "tsc && npm run analyze -- --exclude dist",
39
+ "build:bundle": "esbuild dist/index.js --bundle --outfile=dist/bundle.js --format=esm --platform=browser",
40
+ "release": "npm run build && npm run build:bundle && npm publish --access public",
41
+ "start": "npm run build && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
42
+ "prepublish": "tsc && npm run analyze -- --exclude dist",
43
+ "lint": "eslint --ext .ts,.tsx src --ignore-path .gitignore && prettier \"src/**/*.ts\" --check --ignore-path .gitignore",
44
+ "format": "eslint --ext .ts,.tsx src --fix --ignore-path .gitignore && prettier \"src/**/*.ts\" --write --ignore-path .gitignore",
45
+ "prepare": "husky && husky install",
46
+ "test": "tsc && wtr --coverage",
47
+ "test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\"",
48
+ "storybook": "tsc && npm run analyze -- --exclude dist && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"storybook dev -p 8080\"",
49
+ "storybook:build": "tsc && npm run analyze -- --exclude dist && storybook build"
50
+ },
51
+ "dependencies": {
52
+ "lit": "^3.1.4"
53
+ },
54
+ "devDependencies": {
55
+ "@custom-elements-manifest/analyzer": "^0.10.3",
56
+ "@open-wc/eslint-config": "^12.0.3",
57
+ "@open-wc/testing": "^4.0.0",
58
+ "@storybook/addon-a11y": "^7.6.20",
59
+ "@storybook/addon-essentials": "^7.6.20",
60
+ "@storybook/addon-links": "^7.6.20",
61
+ "@storybook/web-components": "^7.6.20",
62
+ "@types/mocha": "^10.0.7",
63
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
64
+ "@typescript-eslint/parser": "^7.18.0",
65
+ "@web/dev-server": "^0.4.6",
66
+ "@web/storybook-builder": "^0.1.16",
67
+ "@web/storybook-framework-web-components": "^0.1.2",
68
+ "@web/test-runner": "^0.18.2",
69
+ "concurrently": "^8.2.2",
70
+ "esbuild": "^0.25.0",
71
+ "eslint": "^8.57.0",
72
+ "eslint-config-prettier": "^9.1.0",
73
+ "eslint-plugin-html": "^8.1.2",
74
+ "husky": "^8.0.0",
75
+ "lint-staged": "^15.2.7",
76
+ "prettier": "^3.3.2",
77
+ "sinon": "^19.0.2",
78
+ "storybook": "^7.6.20",
79
+ "tslib": "^2.6.3",
80
+ "typescript": "^5.5.3"
81
+ },
82
+ "customElements": "custom-elements.json",
83
+ "eslintConfig": {
84
+ "parser": "@typescript-eslint/parser",
85
+ "extends": [
86
+ "@open-wc",
87
+ "prettier"
88
+ ],
89
+ "plugins": [
90
+ "@typescript-eslint"
91
+ ],
92
+ "rules": {
93
+ "no-unused-vars": "off",
94
+ "@typescript-eslint/no-unused-vars": [
95
+ "error"
96
+ ],
97
+ "import/no-unresolved": "off",
98
+ "import/extensions": [
99
+ "error",
100
+ "always",
101
+ {
102
+ "ignorePackages": true
103
+ }
104
+ ]
105
+ }
106
+ },
107
+ "prettier": {
108
+ "singleQuote": true,
109
+ "arrowParens": "avoid"
110
+ },
111
+ "lint-staged": {
112
+ "*.ts": [
113
+ "eslint --fix",
114
+ "prettier --write"
115
+ ]
116
+ }
117
+ }